18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Montage Technology M88DS3103/M88RS6000 demodulator driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "m88ds3103_priv.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops m88ds3103_ops; 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci/* write single register with mask */ 138c2ecf20Sopenharmony_cistatic int m88ds3103_update_bits(struct m88ds3103_dev *dev, 148c2ecf20Sopenharmony_ci u8 reg, u8 mask, u8 val) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci int ret; 178c2ecf20Sopenharmony_ci u8 tmp; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci /* no need for read if whole reg is written */ 208c2ecf20Sopenharmony_ci if (mask != 0xff) { 218c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap, reg, &tmp, 1); 228c2ecf20Sopenharmony_ci if (ret) 238c2ecf20Sopenharmony_ci return ret; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci val &= mask; 268c2ecf20Sopenharmony_ci tmp &= ~mask; 278c2ecf20Sopenharmony_ci val |= tmp; 288c2ecf20Sopenharmony_ci } 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci return regmap_bulk_write(dev->regmap, reg, &val, 1); 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* write reg val table using reg addr auto increment */ 348c2ecf20Sopenharmony_cistatic int m88ds3103_wr_reg_val_tab(struct m88ds3103_dev *dev, 358c2ecf20Sopenharmony_ci const struct m88ds3103_reg_val *tab, int tab_len) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 388c2ecf20Sopenharmony_ci int ret, i, j; 398c2ecf20Sopenharmony_ci u8 buf[83]; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "tab_len=%d\n", tab_len); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (tab_len > 86) { 448c2ecf20Sopenharmony_ci ret = -EINVAL; 458c2ecf20Sopenharmony_ci goto err; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci for (i = 0, j = 0; i < tab_len; i++, j++) { 498c2ecf20Sopenharmony_ci buf[j] = tab[i].val; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (i == tab_len - 1 || tab[i].reg != tab[i + 1].reg - 1 || 528c2ecf20Sopenharmony_ci !((j + 1) % (dev->cfg->i2c_wr_max - 1))) { 538c2ecf20Sopenharmony_ci ret = regmap_bulk_write(dev->regmap, tab[i].reg - j, buf, j + 1); 548c2ecf20Sopenharmony_ci if (ret) 558c2ecf20Sopenharmony_ci goto err; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci j = -1; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return 0; 628c2ecf20Sopenharmony_cierr: 638c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 648c2ecf20Sopenharmony_ci return ret; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* 688c2ecf20Sopenharmony_ci * m88ds3103b demod has an internal device related to clocking. First the i2c 698c2ecf20Sopenharmony_ci * gate must be opened, for one transaction, then writes will be allowed. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_cistatic int m88ds3103b_dt_write(struct m88ds3103_dev *dev, int reg, int data) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 748c2ecf20Sopenharmony_ci u8 buf[] = {reg, data}; 758c2ecf20Sopenharmony_ci u8 val; 768c2ecf20Sopenharmony_ci int ret; 778c2ecf20Sopenharmony_ci struct i2c_msg msg = { 788c2ecf20Sopenharmony_ci .addr = dev->dt_addr, .flags = 0, .buf = buf, .len = 2 798c2ecf20Sopenharmony_ci }; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci m88ds3103_update_bits(dev, 0x11, 0x01, 0x00); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci val = 0x11; 848c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0x03, val); 858c2ecf20Sopenharmony_ci if (ret) 868c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "fail=%d\n", ret); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci ret = i2c_transfer(dev->dt_client->adapter, &msg, 1); 898c2ecf20Sopenharmony_ci if (ret != 1) { 908c2ecf20Sopenharmony_ci dev_err(&client->dev, "0x%02x (ret=%i, reg=0x%02x, value=0x%02x)\n", 918c2ecf20Sopenharmony_ci dev->dt_addr, ret, reg, data); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); 948c2ecf20Sopenharmony_ci return -EREMOTEIO; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "0x%02x reg 0x%02x, value 0x%02x\n", 998c2ecf20Sopenharmony_ci dev->dt_addr, reg, data); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* 1058c2ecf20Sopenharmony_ci * m88ds3103b demod has an internal device related to clocking. First the i2c 1068c2ecf20Sopenharmony_ci * gate must be opened, for two transactions, then reads will be allowed. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_cistatic int m88ds3103b_dt_read(struct m88ds3103_dev *dev, u8 reg) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 1118c2ecf20Sopenharmony_ci int ret; 1128c2ecf20Sopenharmony_ci u8 val; 1138c2ecf20Sopenharmony_ci u8 b0[] = { reg }; 1148c2ecf20Sopenharmony_ci u8 b1[] = { 0 }; 1158c2ecf20Sopenharmony_ci struct i2c_msg msg[] = { 1168c2ecf20Sopenharmony_ci { 1178c2ecf20Sopenharmony_ci .addr = dev->dt_addr, 1188c2ecf20Sopenharmony_ci .flags = 0, 1198c2ecf20Sopenharmony_ci .buf = b0, 1208c2ecf20Sopenharmony_ci .len = 1 1218c2ecf20Sopenharmony_ci }, 1228c2ecf20Sopenharmony_ci { 1238c2ecf20Sopenharmony_ci .addr = dev->dt_addr, 1248c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 1258c2ecf20Sopenharmony_ci .buf = b1, 1268c2ecf20Sopenharmony_ci .len = 1 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci }; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci m88ds3103_update_bits(dev, 0x11, 0x01, 0x00); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci val = 0x12; 1338c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0x03, val); 1348c2ecf20Sopenharmony_ci if (ret) 1358c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "fail=%d\n", ret); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci ret = i2c_transfer(dev->dt_client->adapter, msg, 2); 1388c2ecf20Sopenharmony_ci if (ret != 2) { 1398c2ecf20Sopenharmony_ci dev_err(&client->dev, "0x%02x (ret=%d, reg=0x%02x)\n", 1408c2ecf20Sopenharmony_ci dev->dt_addr, ret, reg); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); 1438c2ecf20Sopenharmony_ci return -EREMOTEIO; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "0x%02x reg 0x%02x, value 0x%02x\n", 1488c2ecf20Sopenharmony_ci dev->dt_addr, reg, b1[0]); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return b1[0]; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/* 1548c2ecf20Sopenharmony_ci * Get the demodulator AGC PWM voltage setting supplied to the tuner. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ciint m88ds3103_get_agc_pwm(struct dvb_frontend *fe, u8 *_agc_pwm) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = fe->demodulator_priv; 1598c2ecf20Sopenharmony_ci unsigned tmp; 1608c2ecf20Sopenharmony_ci int ret; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap, 0x3f, &tmp); 1638c2ecf20Sopenharmony_ci if (ret == 0) 1648c2ecf20Sopenharmony_ci *_agc_pwm = tmp; 1658c2ecf20Sopenharmony_ci return ret; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(m88ds3103_get_agc_pwm); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int m88ds3103_read_status(struct dvb_frontend *fe, 1708c2ecf20Sopenharmony_ci enum fe_status *status) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = fe->demodulator_priv; 1738c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 1748c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 1758c2ecf20Sopenharmony_ci int ret, i, itmp; 1768c2ecf20Sopenharmony_ci unsigned int utmp; 1778c2ecf20Sopenharmony_ci u8 buf[3]; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci *status = 0; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (!dev->warm) { 1828c2ecf20Sopenharmony_ci ret = -EAGAIN; 1838c2ecf20Sopenharmony_ci goto err; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci switch (c->delivery_system) { 1878c2ecf20Sopenharmony_ci case SYS_DVBS: 1888c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap, 0xd1, &utmp); 1898c2ecf20Sopenharmony_ci if (ret) 1908c2ecf20Sopenharmony_ci goto err; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if ((utmp & 0x07) == 0x07) 1938c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | 1948c2ecf20Sopenharmony_ci FE_HAS_VITERBI | FE_HAS_SYNC | 1958c2ecf20Sopenharmony_ci FE_HAS_LOCK; 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci case SYS_DVBS2: 1988c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap, 0x0d, &utmp); 1998c2ecf20Sopenharmony_ci if (ret) 2008c2ecf20Sopenharmony_ci goto err; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if ((utmp & 0x8f) == 0x8f) 2038c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | 2048c2ecf20Sopenharmony_ci FE_HAS_VITERBI | FE_HAS_SYNC | 2058c2ecf20Sopenharmony_ci FE_HAS_LOCK; 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci default: 2088c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid delivery_system\n"); 2098c2ecf20Sopenharmony_ci ret = -EINVAL; 2108c2ecf20Sopenharmony_ci goto err; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci dev->fe_status = *status; 2148c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "lock=%02x status=%02x\n", utmp, *status); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* CNR */ 2178c2ecf20Sopenharmony_ci if (dev->fe_status & FE_HAS_VITERBI) { 2188c2ecf20Sopenharmony_ci unsigned int cnr, noise, signal, noise_tot, signal_tot; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci cnr = 0; 2218c2ecf20Sopenharmony_ci /* more iterations for more accurate estimation */ 2228c2ecf20Sopenharmony_ci #define M88DS3103_SNR_ITERATIONS 3 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci switch (c->delivery_system) { 2258c2ecf20Sopenharmony_ci case SYS_DVBS: 2268c2ecf20Sopenharmony_ci itmp = 0; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci for (i = 0; i < M88DS3103_SNR_ITERATIONS; i++) { 2298c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap, 0xff, &utmp); 2308c2ecf20Sopenharmony_ci if (ret) 2318c2ecf20Sopenharmony_ci goto err; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci itmp += utmp; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* use of single register limits max value to 15 dB */ 2378c2ecf20Sopenharmony_ci /* SNR(X) dB = 10 * ln(X) / ln(10) dB */ 2388c2ecf20Sopenharmony_ci itmp = DIV_ROUND_CLOSEST(itmp, 8 * M88DS3103_SNR_ITERATIONS); 2398c2ecf20Sopenharmony_ci if (itmp) 2408c2ecf20Sopenharmony_ci cnr = div_u64((u64) 10000 * intlog2(itmp), intlog2(10)); 2418c2ecf20Sopenharmony_ci break; 2428c2ecf20Sopenharmony_ci case SYS_DVBS2: 2438c2ecf20Sopenharmony_ci noise_tot = 0; 2448c2ecf20Sopenharmony_ci signal_tot = 0; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci for (i = 0; i < M88DS3103_SNR_ITERATIONS; i++) { 2478c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap, 0x8c, buf, 3); 2488c2ecf20Sopenharmony_ci if (ret) 2498c2ecf20Sopenharmony_ci goto err; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci noise = buf[1] << 6; /* [13:6] */ 2528c2ecf20Sopenharmony_ci noise |= buf[0] & 0x3f; /* [5:0] */ 2538c2ecf20Sopenharmony_ci noise >>= 2; 2548c2ecf20Sopenharmony_ci signal = buf[2] * buf[2]; 2558c2ecf20Sopenharmony_ci signal >>= 1; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci noise_tot += noise; 2588c2ecf20Sopenharmony_ci signal_tot += signal; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci noise = noise_tot / M88DS3103_SNR_ITERATIONS; 2628c2ecf20Sopenharmony_ci signal = signal_tot / M88DS3103_SNR_ITERATIONS; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* SNR(X) dB = 10 * log10(X) dB */ 2658c2ecf20Sopenharmony_ci if (signal > noise) { 2668c2ecf20Sopenharmony_ci itmp = signal / noise; 2678c2ecf20Sopenharmony_ci cnr = div_u64((u64) 10000 * intlog10(itmp), (1 << 24)); 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci default: 2718c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid delivery_system\n"); 2728c2ecf20Sopenharmony_ci ret = -EINVAL; 2738c2ecf20Sopenharmony_ci goto err; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (cnr) { 2778c2ecf20Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 2788c2ecf20Sopenharmony_ci c->cnr.stat[0].svalue = cnr; 2798c2ecf20Sopenharmony_ci } else { 2808c2ecf20Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci } else { 2838c2ecf20Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* BER */ 2878c2ecf20Sopenharmony_ci if (dev->fe_status & FE_HAS_LOCK) { 2888c2ecf20Sopenharmony_ci unsigned int utmp, post_bit_error, post_bit_count; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci switch (c->delivery_system) { 2918c2ecf20Sopenharmony_ci case SYS_DVBS: 2928c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xf9, 0x04); 2938c2ecf20Sopenharmony_ci if (ret) 2948c2ecf20Sopenharmony_ci goto err; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap, 0xf8, &utmp); 2978c2ecf20Sopenharmony_ci if (ret) 2988c2ecf20Sopenharmony_ci goto err; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* measurement ready? */ 3018c2ecf20Sopenharmony_ci if (!(utmp & 0x10)) { 3028c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap, 0xf6, buf, 2); 3038c2ecf20Sopenharmony_ci if (ret) 3048c2ecf20Sopenharmony_ci goto err; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci post_bit_error = buf[1] << 8 | buf[0] << 0; 3078c2ecf20Sopenharmony_ci post_bit_count = 0x800000; 3088c2ecf20Sopenharmony_ci dev->post_bit_error += post_bit_error; 3098c2ecf20Sopenharmony_ci dev->post_bit_count += post_bit_count; 3108c2ecf20Sopenharmony_ci dev->dvbv3_ber = post_bit_error; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* restart measurement */ 3138c2ecf20Sopenharmony_ci utmp |= 0x10; 3148c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xf8, utmp); 3158c2ecf20Sopenharmony_ci if (ret) 3168c2ecf20Sopenharmony_ci goto err; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci break; 3198c2ecf20Sopenharmony_ci case SYS_DVBS2: 3208c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap, 0xd5, buf, 3); 3218c2ecf20Sopenharmony_ci if (ret) 3228c2ecf20Sopenharmony_ci goto err; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci utmp = buf[2] << 16 | buf[1] << 8 | buf[0] << 0; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* enough data? */ 3278c2ecf20Sopenharmony_ci if (utmp > 4000) { 3288c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap, 0xf7, buf, 2); 3298c2ecf20Sopenharmony_ci if (ret) 3308c2ecf20Sopenharmony_ci goto err; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci post_bit_error = buf[1] << 8 | buf[0] << 0; 3338c2ecf20Sopenharmony_ci post_bit_count = 32 * utmp; /* TODO: FEC */ 3348c2ecf20Sopenharmony_ci dev->post_bit_error += post_bit_error; 3358c2ecf20Sopenharmony_ci dev->post_bit_count += post_bit_count; 3368c2ecf20Sopenharmony_ci dev->dvbv3_ber = post_bit_error; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* restart measurement */ 3398c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xd1, 0x01); 3408c2ecf20Sopenharmony_ci if (ret) 3418c2ecf20Sopenharmony_ci goto err; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xf9, 0x01); 3448c2ecf20Sopenharmony_ci if (ret) 3458c2ecf20Sopenharmony_ci goto err; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xf9, 0x00); 3488c2ecf20Sopenharmony_ci if (ret) 3498c2ecf20Sopenharmony_ci goto err; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xd1, 0x00); 3528c2ecf20Sopenharmony_ci if (ret) 3538c2ecf20Sopenharmony_ci goto err; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci default: 3578c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid delivery_system\n"); 3588c2ecf20Sopenharmony_ci ret = -EINVAL; 3598c2ecf20Sopenharmony_ci goto err; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; 3638c2ecf20Sopenharmony_ci c->post_bit_error.stat[0].uvalue = dev->post_bit_error; 3648c2ecf20Sopenharmony_ci c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; 3658c2ecf20Sopenharmony_ci c->post_bit_count.stat[0].uvalue = dev->post_bit_count; 3668c2ecf20Sopenharmony_ci } else { 3678c2ecf20Sopenharmony_ci c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 3688c2ecf20Sopenharmony_ci c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_cierr: 3738c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 3748c2ecf20Sopenharmony_ci return ret; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic int m88ds3103b_select_mclk(struct m88ds3103_dev *dev) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 3808c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; 3818c2ecf20Sopenharmony_ci u32 adc_Freq_MHz[3] = {96, 93, 99}; 3828c2ecf20Sopenharmony_ci u8 reg16_list[3] = {96, 92, 100}, reg16, reg15; 3838c2ecf20Sopenharmony_ci u32 offset_MHz[3]; 3848c2ecf20Sopenharmony_ci u32 max_offset = 0; 3858c2ecf20Sopenharmony_ci u32 old_setting = dev->mclk; 3868c2ecf20Sopenharmony_ci u32 tuner_freq_MHz = c->frequency / 1000; 3878c2ecf20Sopenharmony_ci u8 i; 3888c2ecf20Sopenharmony_ci char big_symbol = 0; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci big_symbol = (c->symbol_rate > 45010000) ? 1 : 0; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (big_symbol) { 3938c2ecf20Sopenharmony_ci reg16 = 115; 3948c2ecf20Sopenharmony_ci } else { 3958c2ecf20Sopenharmony_ci reg16 = 96; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* TODO: IS THIS NECESSARY ? */ 3988c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 3998c2ecf20Sopenharmony_ci offset_MHz[i] = tuner_freq_MHz % adc_Freq_MHz[i]; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (offset_MHz[i] > (adc_Freq_MHz[i] / 2)) 4028c2ecf20Sopenharmony_ci offset_MHz[i] = adc_Freq_MHz[i] - offset_MHz[i]; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (offset_MHz[i] > max_offset) { 4058c2ecf20Sopenharmony_ci max_offset = offset_MHz[i]; 4068c2ecf20Sopenharmony_ci reg16 = reg16_list[i]; 4078c2ecf20Sopenharmony_ci dev->mclk = adc_Freq_MHz[i] * 1000 * 1000; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (big_symbol) 4108c2ecf20Sopenharmony_ci dev->mclk /= 2; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "modifying mclk %u -> %u\n", 4138c2ecf20Sopenharmony_ci old_setting, dev->mclk); 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (dev->mclk == 93000000) 4198c2ecf20Sopenharmony_ci regmap_write(dev->regmap, 0xA0, 0x42); 4208c2ecf20Sopenharmony_ci else if (dev->mclk == 96000000) 4218c2ecf20Sopenharmony_ci regmap_write(dev->regmap, 0xA0, 0x44); 4228c2ecf20Sopenharmony_ci else if (dev->mclk == 99000000) 4238c2ecf20Sopenharmony_ci regmap_write(dev->regmap, 0xA0, 0x46); 4248c2ecf20Sopenharmony_ci else if (dev->mclk == 110250000) 4258c2ecf20Sopenharmony_ci regmap_write(dev->regmap, 0xA0, 0x4E); 4268c2ecf20Sopenharmony_ci else 4278c2ecf20Sopenharmony_ci regmap_write(dev->regmap, 0xA0, 0x44); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci reg15 = m88ds3103b_dt_read(dev, 0x15); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x05, 0x40); 4328c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x11, 0x08); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (big_symbol) 4358c2ecf20Sopenharmony_ci reg15 |= 0x02; 4368c2ecf20Sopenharmony_ci else 4378c2ecf20Sopenharmony_ci reg15 &= ~0x02; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x15, reg15); 4408c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x16, reg16); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci usleep_range(5000, 5500); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x05, 0x00); 4458c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x11, (u8)(big_symbol ? 0x0E : 0x0A)); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci usleep_range(5000, 5500); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci return 0; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic int m88ds3103b_set_mclk(struct m88ds3103_dev *dev, u32 mclk_khz) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci u8 reg11 = 0x0A, reg15, reg16, reg1D, reg1E, reg1F, tmp; 4558c2ecf20Sopenharmony_ci u8 sm, f0 = 0, f1 = 0, f2 = 0, f3 = 0; 4568c2ecf20Sopenharmony_ci u16 pll_div_fb, N; 4578c2ecf20Sopenharmony_ci u32 div; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci reg15 = m88ds3103b_dt_read(dev, 0x15); 4608c2ecf20Sopenharmony_ci reg16 = m88ds3103b_dt_read(dev, 0x16); 4618c2ecf20Sopenharmony_ci reg1D = m88ds3103b_dt_read(dev, 0x1D); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (dev->cfg->ts_mode != M88DS3103_TS_SERIAL) { 4648c2ecf20Sopenharmony_ci if (reg16 == 92) 4658c2ecf20Sopenharmony_ci tmp = 93; 4668c2ecf20Sopenharmony_ci else if (reg16 == 100) 4678c2ecf20Sopenharmony_ci tmp = 99; 4688c2ecf20Sopenharmony_ci else 4698c2ecf20Sopenharmony_ci tmp = 96; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci mclk_khz *= tmp; 4728c2ecf20Sopenharmony_ci mclk_khz /= 96; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci pll_div_fb = (reg15 & 0x01) << 8; 4768c2ecf20Sopenharmony_ci pll_div_fb += reg16; 4778c2ecf20Sopenharmony_ci pll_div_fb += 32; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci div = 9000 * pll_div_fb * 4; 4808c2ecf20Sopenharmony_ci div /= mclk_khz; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (dev->cfg->ts_mode == M88DS3103_TS_SERIAL) { 4838c2ecf20Sopenharmony_ci reg11 |= 0x02; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (div <= 32) { 4868c2ecf20Sopenharmony_ci N = 2; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci f0 = 0; 4898c2ecf20Sopenharmony_ci f1 = div / N; 4908c2ecf20Sopenharmony_ci f2 = div - f1; 4918c2ecf20Sopenharmony_ci f3 = 0; 4928c2ecf20Sopenharmony_ci } else if (div <= 34) { 4938c2ecf20Sopenharmony_ci N = 3; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci f0 = div / N; 4968c2ecf20Sopenharmony_ci f1 = (div - f0) / (N - 1); 4978c2ecf20Sopenharmony_ci f2 = div - f0 - f1; 4988c2ecf20Sopenharmony_ci f3 = 0; 4998c2ecf20Sopenharmony_ci } else if (div <= 64) { 5008c2ecf20Sopenharmony_ci N = 4; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci f0 = div / N; 5038c2ecf20Sopenharmony_ci f1 = (div - f0) / (N - 1); 5048c2ecf20Sopenharmony_ci f2 = (div - f0 - f1) / (N - 2); 5058c2ecf20Sopenharmony_ci f3 = div - f0 - f1 - f2; 5068c2ecf20Sopenharmony_ci } else { 5078c2ecf20Sopenharmony_ci N = 4; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci f0 = 16; 5108c2ecf20Sopenharmony_ci f1 = 16; 5118c2ecf20Sopenharmony_ci f2 = 16; 5128c2ecf20Sopenharmony_ci f3 = 16; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (f0 == 16) 5168c2ecf20Sopenharmony_ci f0 = 0; 5178c2ecf20Sopenharmony_ci else if ((f0 < 8) && (f0 != 0)) 5188c2ecf20Sopenharmony_ci f0 = 8; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (f1 == 16) 5218c2ecf20Sopenharmony_ci f1 = 0; 5228c2ecf20Sopenharmony_ci else if ((f1 < 8) && (f1 != 0)) 5238c2ecf20Sopenharmony_ci f1 = 8; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (f2 == 16) 5268c2ecf20Sopenharmony_ci f2 = 0; 5278c2ecf20Sopenharmony_ci else if ((f2 < 8) && (f2 != 0)) 5288c2ecf20Sopenharmony_ci f2 = 8; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (f3 == 16) 5318c2ecf20Sopenharmony_ci f3 = 0; 5328c2ecf20Sopenharmony_ci else if ((f3 < 8) && (f3 != 0)) 5338c2ecf20Sopenharmony_ci f3 = 8; 5348c2ecf20Sopenharmony_ci } else { 5358c2ecf20Sopenharmony_ci reg11 &= ~0x02; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (div <= 32) { 5388c2ecf20Sopenharmony_ci N = 2; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci f0 = 0; 5418c2ecf20Sopenharmony_ci f1 = div / N; 5428c2ecf20Sopenharmony_ci f2 = div - f1; 5438c2ecf20Sopenharmony_ci f3 = 0; 5448c2ecf20Sopenharmony_ci } else if (div <= 48) { 5458c2ecf20Sopenharmony_ci N = 3; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci f0 = div / N; 5488c2ecf20Sopenharmony_ci f1 = (div - f0) / (N - 1); 5498c2ecf20Sopenharmony_ci f2 = div - f0 - f1; 5508c2ecf20Sopenharmony_ci f3 = 0; 5518c2ecf20Sopenharmony_ci } else if (div <= 64) { 5528c2ecf20Sopenharmony_ci N = 4; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci f0 = div / N; 5558c2ecf20Sopenharmony_ci f1 = (div - f0) / (N - 1); 5568c2ecf20Sopenharmony_ci f2 = (div - f0 - f1) / (N - 2); 5578c2ecf20Sopenharmony_ci f3 = div - f0 - f1 - f2; 5588c2ecf20Sopenharmony_ci } else { 5598c2ecf20Sopenharmony_ci N = 4; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci f0 = 16; 5628c2ecf20Sopenharmony_ci f1 = 16; 5638c2ecf20Sopenharmony_ci f2 = 16; 5648c2ecf20Sopenharmony_ci f3 = 16; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (f0 == 16) 5688c2ecf20Sopenharmony_ci f0 = 0; 5698c2ecf20Sopenharmony_ci else if ((f0 < 9) && (f0 != 0)) 5708c2ecf20Sopenharmony_ci f0 = 9; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (f1 == 16) 5738c2ecf20Sopenharmony_ci f1 = 0; 5748c2ecf20Sopenharmony_ci else if ((f1 < 9) && (f1 != 0)) 5758c2ecf20Sopenharmony_ci f1 = 9; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (f2 == 16) 5788c2ecf20Sopenharmony_ci f2 = 0; 5798c2ecf20Sopenharmony_ci else if ((f2 < 9) && (f2 != 0)) 5808c2ecf20Sopenharmony_ci f2 = 9; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (f3 == 16) 5838c2ecf20Sopenharmony_ci f3 = 0; 5848c2ecf20Sopenharmony_ci else if ((f3 < 9) && (f3 != 0)) 5858c2ecf20Sopenharmony_ci f3 = 9; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci sm = N - 1; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci /* Write to registers */ 5918c2ecf20Sopenharmony_ci //reg15 &= 0x01; 5928c2ecf20Sopenharmony_ci //reg15 |= (pll_div_fb >> 8) & 0x01; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci //reg16 = pll_div_fb & 0xFF; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci reg1D &= ~0x03; 5978c2ecf20Sopenharmony_ci reg1D |= sm; 5988c2ecf20Sopenharmony_ci reg1D |= 0x80; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci reg1E = ((f3 << 4) + f2) & 0xFF; 6018c2ecf20Sopenharmony_ci reg1F = ((f1 << 4) + f0) & 0xFF; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x05, 0x40); 6048c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x11, 0x08); 6058c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x1D, reg1D); 6068c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x1E, reg1E); 6078c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x1F, reg1F); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x17, 0xc1); 6108c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x17, 0x81); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci usleep_range(5000, 5500); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x05, 0x00); 6158c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x11, 0x0A); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci usleep_range(5000, 5500); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci return 0; 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic int m88ds3103_set_frontend(struct dvb_frontend *fe) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = fe->demodulator_priv; 6258c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 6268c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 6278c2ecf20Sopenharmony_ci int ret, len; 6288c2ecf20Sopenharmony_ci const struct m88ds3103_reg_val *init; 6298c2ecf20Sopenharmony_ci u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */ 6308c2ecf20Sopenharmony_ci u8 buf[3]; 6318c2ecf20Sopenharmony_ci u16 u16tmp; 6328c2ecf20Sopenharmony_ci u32 tuner_frequency_khz, target_mclk, u32tmp; 6338c2ecf20Sopenharmony_ci s32 s32tmp; 6348c2ecf20Sopenharmony_ci static const struct reg_sequence reset_buf[] = { 6358c2ecf20Sopenharmony_ci {0x07, 0x80}, {0x07, 0x00} 6368c2ecf20Sopenharmony_ci }; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci dev_dbg(&client->dev, 6398c2ecf20Sopenharmony_ci "delivery_system=%d modulation=%d frequency=%u symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n", 6408c2ecf20Sopenharmony_ci c->delivery_system, c->modulation, c->frequency, c->symbol_rate, 6418c2ecf20Sopenharmony_ci c->inversion, c->pilot, c->rolloff); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (!dev->warm) { 6448c2ecf20Sopenharmony_ci ret = -EAGAIN; 6458c2ecf20Sopenharmony_ci goto err; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci /* reset */ 6498c2ecf20Sopenharmony_ci ret = regmap_multi_reg_write(dev->regmap, reset_buf, 2); 6508c2ecf20Sopenharmony_ci if (ret) 6518c2ecf20Sopenharmony_ci goto err; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci /* Disable demod clock path */ 6548c2ecf20Sopenharmony_ci if (dev->chip_id == M88RS6000_CHIP_ID) { 6558c2ecf20Sopenharmony_ci if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { 6568c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap, 0xb2, &u32tmp); 6578c2ecf20Sopenharmony_ci if (ret) 6588c2ecf20Sopenharmony_ci goto err; 6598c2ecf20Sopenharmony_ci if (u32tmp == 0x01) { 6608c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0x00, 0x00); 6618c2ecf20Sopenharmony_ci if (ret) 6628c2ecf20Sopenharmony_ci goto err; 6638c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xb2, 0x00); 6648c2ecf20Sopenharmony_ci if (ret) 6658c2ecf20Sopenharmony_ci goto err; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0x06, 0xe0); 6708c2ecf20Sopenharmony_ci if (ret) 6718c2ecf20Sopenharmony_ci goto err; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* program tuner */ 6758c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params) { 6768c2ecf20Sopenharmony_ci ret = fe->ops.tuner_ops.set_params(fe); 6778c2ecf20Sopenharmony_ci if (ret) 6788c2ecf20Sopenharmony_ci goto err; 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.get_frequency) { 6828c2ecf20Sopenharmony_ci ret = fe->ops.tuner_ops.get_frequency(fe, &tuner_frequency_khz); 6838c2ecf20Sopenharmony_ci if (ret) 6848c2ecf20Sopenharmony_ci goto err; 6858c2ecf20Sopenharmony_ci } else { 6868c2ecf20Sopenharmony_ci /* 6878c2ecf20Sopenharmony_ci * Use nominal target frequency as tuner driver does not provide 6888c2ecf20Sopenharmony_ci * actual frequency used. Carrier offset calculation is not 6898c2ecf20Sopenharmony_ci * valid. 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_ci tuner_frequency_khz = c->frequency; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* set M88RS6000/DS3103B demod main mclk and ts mclk from tuner die */ 6958c2ecf20Sopenharmony_ci if (dev->chip_id == M88RS6000_CHIP_ID) { 6968c2ecf20Sopenharmony_ci if (c->symbol_rate > 45010000) 6978c2ecf20Sopenharmony_ci dev->mclk = 110250000; 6988c2ecf20Sopenharmony_ci else 6998c2ecf20Sopenharmony_ci dev->mclk = 96000000; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (c->delivery_system == SYS_DVBS) 7028c2ecf20Sopenharmony_ci target_mclk = 96000000; 7038c2ecf20Sopenharmony_ci else 7048c2ecf20Sopenharmony_ci target_mclk = 144000000; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { 7078c2ecf20Sopenharmony_ci m88ds3103b_select_mclk(dev); 7088c2ecf20Sopenharmony_ci m88ds3103b_set_mclk(dev, target_mclk / 1000); 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci /* Enable demod clock path */ 7128c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0x06, 0x00); 7138c2ecf20Sopenharmony_ci if (ret) 7148c2ecf20Sopenharmony_ci goto err; 7158c2ecf20Sopenharmony_ci usleep_range(10000, 20000); 7168c2ecf20Sopenharmony_ci } else { 7178c2ecf20Sopenharmony_ci /* set M88DS3103 mclk and ts mclk. */ 7188c2ecf20Sopenharmony_ci dev->mclk = 96000000; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci switch (dev->cfg->ts_mode) { 7218c2ecf20Sopenharmony_ci case M88DS3103_TS_SERIAL: 7228c2ecf20Sopenharmony_ci case M88DS3103_TS_SERIAL_D7: 7238c2ecf20Sopenharmony_ci target_mclk = dev->cfg->ts_clk; 7248c2ecf20Sopenharmony_ci break; 7258c2ecf20Sopenharmony_ci case M88DS3103_TS_PARALLEL: 7268c2ecf20Sopenharmony_ci case M88DS3103_TS_CI: 7278c2ecf20Sopenharmony_ci if (c->delivery_system == SYS_DVBS) 7288c2ecf20Sopenharmony_ci target_mclk = 96000000; 7298c2ecf20Sopenharmony_ci else { 7308c2ecf20Sopenharmony_ci if (c->symbol_rate < 18000000) 7318c2ecf20Sopenharmony_ci target_mclk = 96000000; 7328c2ecf20Sopenharmony_ci else if (c->symbol_rate < 28000000) 7338c2ecf20Sopenharmony_ci target_mclk = 144000000; 7348c2ecf20Sopenharmony_ci else 7358c2ecf20Sopenharmony_ci target_mclk = 192000000; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci break; 7388c2ecf20Sopenharmony_ci default: 7398c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid ts_mode\n"); 7408c2ecf20Sopenharmony_ci ret = -EINVAL; 7418c2ecf20Sopenharmony_ci goto err; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci switch (target_mclk) { 7458c2ecf20Sopenharmony_ci case 96000000: 7468c2ecf20Sopenharmony_ci u8tmp1 = 0x02; /* 0b10 */ 7478c2ecf20Sopenharmony_ci u8tmp2 = 0x01; /* 0b01 */ 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci case 144000000: 7508c2ecf20Sopenharmony_ci u8tmp1 = 0x00; /* 0b00 */ 7518c2ecf20Sopenharmony_ci u8tmp2 = 0x01; /* 0b01 */ 7528c2ecf20Sopenharmony_ci break; 7538c2ecf20Sopenharmony_ci case 192000000: 7548c2ecf20Sopenharmony_ci u8tmp1 = 0x03; /* 0b11 */ 7558c2ecf20Sopenharmony_ci u8tmp2 = 0x00; /* 0b00 */ 7568c2ecf20Sopenharmony_ci break; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x22, 0xc0, u8tmp1 << 6); 7598c2ecf20Sopenharmony_ci if (ret) 7608c2ecf20Sopenharmony_ci goto err; 7618c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x24, 0xc0, u8tmp2 << 6); 7628c2ecf20Sopenharmony_ci if (ret) 7638c2ecf20Sopenharmony_ci goto err; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xb2, 0x01); 7678c2ecf20Sopenharmony_ci if (ret) 7688c2ecf20Sopenharmony_ci goto err; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0x00, 0x01); 7718c2ecf20Sopenharmony_ci if (ret) 7728c2ecf20Sopenharmony_ci goto err; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci switch (c->delivery_system) { 7758c2ecf20Sopenharmony_ci case SYS_DVBS: 7768c2ecf20Sopenharmony_ci if (dev->chip_id == M88RS6000_CHIP_ID) { 7778c2ecf20Sopenharmony_ci len = ARRAY_SIZE(m88rs6000_dvbs_init_reg_vals); 7788c2ecf20Sopenharmony_ci init = m88rs6000_dvbs_init_reg_vals; 7798c2ecf20Sopenharmony_ci } else { 7808c2ecf20Sopenharmony_ci len = ARRAY_SIZE(m88ds3103_dvbs_init_reg_vals); 7818c2ecf20Sopenharmony_ci init = m88ds3103_dvbs_init_reg_vals; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci break; 7848c2ecf20Sopenharmony_ci case SYS_DVBS2: 7858c2ecf20Sopenharmony_ci if (dev->chip_id == M88RS6000_CHIP_ID) { 7868c2ecf20Sopenharmony_ci len = ARRAY_SIZE(m88rs6000_dvbs2_init_reg_vals); 7878c2ecf20Sopenharmony_ci init = m88rs6000_dvbs2_init_reg_vals; 7888c2ecf20Sopenharmony_ci } else { 7898c2ecf20Sopenharmony_ci len = ARRAY_SIZE(m88ds3103_dvbs2_init_reg_vals); 7908c2ecf20Sopenharmony_ci init = m88ds3103_dvbs2_init_reg_vals; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci break; 7938c2ecf20Sopenharmony_ci default: 7948c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid delivery_system\n"); 7958c2ecf20Sopenharmony_ci ret = -EINVAL; 7968c2ecf20Sopenharmony_ci goto err; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* program init table */ 8008c2ecf20Sopenharmony_ci if (c->delivery_system != dev->delivery_system) { 8018c2ecf20Sopenharmony_ci ret = m88ds3103_wr_reg_val_tab(dev, init, len); 8028c2ecf20Sopenharmony_ci if (ret) 8038c2ecf20Sopenharmony_ci goto err; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (dev->chip_id == M88RS6000_CHIP_ID) { 8078c2ecf20Sopenharmony_ci if (c->delivery_system == SYS_DVBS2 && 8088c2ecf20Sopenharmony_ci c->symbol_rate <= 5000000) { 8098c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xc0, 0x04); 8108c2ecf20Sopenharmony_ci if (ret) 8118c2ecf20Sopenharmony_ci goto err; 8128c2ecf20Sopenharmony_ci buf[0] = 0x09; 8138c2ecf20Sopenharmony_ci buf[1] = 0x22; 8148c2ecf20Sopenharmony_ci buf[2] = 0x88; 8158c2ecf20Sopenharmony_ci ret = regmap_bulk_write(dev->regmap, 0x8a, buf, 3); 8168c2ecf20Sopenharmony_ci if (ret) 8178c2ecf20Sopenharmony_ci goto err; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x9d, 0x08, 0x08); 8208c2ecf20Sopenharmony_ci if (ret) 8218c2ecf20Sopenharmony_ci goto err; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { 8248c2ecf20Sopenharmony_ci buf[0] = m88ds3103b_dt_read(dev, 0x15); 8258c2ecf20Sopenharmony_ci buf[1] = m88ds3103b_dt_read(dev, 0x16); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (c->symbol_rate > 45010000) { 8288c2ecf20Sopenharmony_ci buf[0] &= ~0x03; 8298c2ecf20Sopenharmony_ci buf[0] |= 0x02; 8308c2ecf20Sopenharmony_ci buf[0] |= ((147 - 32) >> 8) & 0x01; 8318c2ecf20Sopenharmony_ci buf[1] = (147 - 32) & 0xFF; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci dev->mclk = 110250 * 1000; 8348c2ecf20Sopenharmony_ci } else { 8358c2ecf20Sopenharmony_ci buf[0] &= ~0x03; 8368c2ecf20Sopenharmony_ci buf[0] |= ((128 - 32) >> 8) & 0x01; 8378c2ecf20Sopenharmony_ci buf[1] = (128 - 32) & 0xFF; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci dev->mclk = 96000 * 1000; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x15, buf[0]); 8428c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x16, buf[1]); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci regmap_read(dev->regmap, 0x30, &u32tmp); 8458c2ecf20Sopenharmony_ci u32tmp &= ~0x80; 8468c2ecf20Sopenharmony_ci regmap_write(dev->regmap, 0x30, u32tmp & 0xff); 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xf1, 0x01); 8508c2ecf20Sopenharmony_ci if (ret) 8518c2ecf20Sopenharmony_ci goto err; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (dev->chiptype != M88DS3103_CHIPTYPE_3103B) { 8548c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80); 8558c2ecf20Sopenharmony_ci if (ret) 8568c2ecf20Sopenharmony_ci goto err; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci switch (dev->cfg->ts_mode) { 8618c2ecf20Sopenharmony_ci case M88DS3103_TS_SERIAL: 8628c2ecf20Sopenharmony_ci u8tmp1 = 0x00; 8638c2ecf20Sopenharmony_ci u8tmp = 0x06; 8648c2ecf20Sopenharmony_ci break; 8658c2ecf20Sopenharmony_ci case M88DS3103_TS_SERIAL_D7: 8668c2ecf20Sopenharmony_ci u8tmp1 = 0x20; 8678c2ecf20Sopenharmony_ci u8tmp = 0x06; 8688c2ecf20Sopenharmony_ci break; 8698c2ecf20Sopenharmony_ci case M88DS3103_TS_PARALLEL: 8708c2ecf20Sopenharmony_ci u8tmp = 0x02; 8718c2ecf20Sopenharmony_ci if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { 8728c2ecf20Sopenharmony_ci u8tmp = 0x01; 8738c2ecf20Sopenharmony_ci u8tmp1 = 0x01; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci break; 8768c2ecf20Sopenharmony_ci case M88DS3103_TS_CI: 8778c2ecf20Sopenharmony_ci u8tmp = 0x03; 8788c2ecf20Sopenharmony_ci break; 8798c2ecf20Sopenharmony_ci default: 8808c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid ts_mode\n"); 8818c2ecf20Sopenharmony_ci ret = -EINVAL; 8828c2ecf20Sopenharmony_ci goto err; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (dev->cfg->ts_clk_pol) 8868c2ecf20Sopenharmony_ci u8tmp |= 0x40; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* TS mode */ 8898c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xfd, u8tmp); 8908c2ecf20Sopenharmony_ci if (ret) 8918c2ecf20Sopenharmony_ci goto err; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci switch (dev->cfg->ts_mode) { 8948c2ecf20Sopenharmony_ci case M88DS3103_TS_SERIAL: 8958c2ecf20Sopenharmony_ci case M88DS3103_TS_SERIAL_D7: 8968c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x29, 0x20, u8tmp1); 8978c2ecf20Sopenharmony_ci if (ret) 8988c2ecf20Sopenharmony_ci goto err; 8998c2ecf20Sopenharmony_ci u16tmp = 0; 9008c2ecf20Sopenharmony_ci u8tmp1 = 0x3f; 9018c2ecf20Sopenharmony_ci u8tmp2 = 0x3f; 9028c2ecf20Sopenharmony_ci break; 9038c2ecf20Sopenharmony_ci case M88DS3103_TS_PARALLEL: 9048c2ecf20Sopenharmony_ci if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { 9058c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x29, 0x01, u8tmp1); 9068c2ecf20Sopenharmony_ci if (ret) 9078c2ecf20Sopenharmony_ci goto err; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci fallthrough; 9108c2ecf20Sopenharmony_ci default: 9118c2ecf20Sopenharmony_ci u16tmp = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk); 9128c2ecf20Sopenharmony_ci u8tmp1 = u16tmp / 2 - 1; 9138c2ecf20Sopenharmony_ci u8tmp2 = DIV_ROUND_UP(u16tmp, 2) - 1; 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "target_mclk=%u ts_clk=%u ts_clk_divide_ratio=%u\n", 9178c2ecf20Sopenharmony_ci target_mclk, dev->cfg->ts_clk, u16tmp); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci /* u8tmp1[5:2] => fe[3:0], u8tmp1[1:0] => ea[7:6] */ 9208c2ecf20Sopenharmony_ci /* u8tmp2[5:0] => ea[5:0] */ 9218c2ecf20Sopenharmony_ci u8tmp = (u8tmp1 >> 2) & 0x0f; 9228c2ecf20Sopenharmony_ci ret = regmap_update_bits(dev->regmap, 0xfe, 0x0f, u8tmp); 9238c2ecf20Sopenharmony_ci if (ret) 9248c2ecf20Sopenharmony_ci goto err; 9258c2ecf20Sopenharmony_ci u8tmp = ((u8tmp1 & 0x03) << 6) | u8tmp2 >> 0; 9268c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xea, u8tmp); 9278c2ecf20Sopenharmony_ci if (ret) 9288c2ecf20Sopenharmony_ci goto err; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (c->symbol_rate <= 3000000) 9318c2ecf20Sopenharmony_ci u8tmp = 0x20; 9328c2ecf20Sopenharmony_ci else if (c->symbol_rate <= 10000000) 9338c2ecf20Sopenharmony_ci u8tmp = 0x10; 9348c2ecf20Sopenharmony_ci else 9358c2ecf20Sopenharmony_ci u8tmp = 0x06; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) 9388c2ecf20Sopenharmony_ci m88ds3103b_set_mclk(dev, target_mclk / 1000); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xc3, 0x08); 9418c2ecf20Sopenharmony_ci if (ret) 9428c2ecf20Sopenharmony_ci goto err; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xc8, u8tmp); 9458c2ecf20Sopenharmony_ci if (ret) 9468c2ecf20Sopenharmony_ci goto err; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xc4, 0x08); 9498c2ecf20Sopenharmony_ci if (ret) 9508c2ecf20Sopenharmony_ci goto err; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xc7, 0x00); 9538c2ecf20Sopenharmony_ci if (ret) 9548c2ecf20Sopenharmony_ci goto err; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci u16tmp = DIV_ROUND_CLOSEST_ULL((u64)c->symbol_rate * 0x10000, dev->mclk); 9578c2ecf20Sopenharmony_ci buf[0] = (u16tmp >> 0) & 0xff; 9588c2ecf20Sopenharmony_ci buf[1] = (u16tmp >> 8) & 0xff; 9598c2ecf20Sopenharmony_ci ret = regmap_bulk_write(dev->regmap, 0x61, buf, 2); 9608c2ecf20Sopenharmony_ci if (ret) 9618c2ecf20Sopenharmony_ci goto err; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x4d, 0x02, dev->cfg->spec_inv << 1); 9648c2ecf20Sopenharmony_ci if (ret) 9658c2ecf20Sopenharmony_ci goto err; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x30, 0x10, dev->cfg->agc_inv << 4); 9688c2ecf20Sopenharmony_ci if (ret) 9698c2ecf20Sopenharmony_ci goto err; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0x33, dev->cfg->agc); 9728c2ecf20Sopenharmony_ci if (ret) 9738c2ecf20Sopenharmony_ci goto err; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { 9768c2ecf20Sopenharmony_ci /* enable/disable 192M LDPC clock */ 9778c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x29, 0x10, 9788c2ecf20Sopenharmony_ci (c->delivery_system == SYS_DVBS) ? 0x10 : 0x0); 9798c2ecf20Sopenharmony_ci if (ret) 9808c2ecf20Sopenharmony_ci goto err; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0xc9, 0x08, 0x08); 9838c2ecf20Sopenharmony_ci if (ret) 9848c2ecf20Sopenharmony_ci goto err; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "carrier offset=%d\n", 9888c2ecf20Sopenharmony_ci (tuner_frequency_khz - c->frequency)); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* Use 32-bit calc as there is no s64 version of DIV_ROUND_CLOSEST() */ 9918c2ecf20Sopenharmony_ci s32tmp = 0x10000 * (tuner_frequency_khz - c->frequency); 9928c2ecf20Sopenharmony_ci s32tmp = DIV_ROUND_CLOSEST(s32tmp, dev->mclk / 1000); 9938c2ecf20Sopenharmony_ci buf[0] = (s32tmp >> 0) & 0xff; 9948c2ecf20Sopenharmony_ci buf[1] = (s32tmp >> 8) & 0xff; 9958c2ecf20Sopenharmony_ci ret = regmap_bulk_write(dev->regmap, 0x5e, buf, 2); 9968c2ecf20Sopenharmony_ci if (ret) 9978c2ecf20Sopenharmony_ci goto err; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0x00, 0x00); 10008c2ecf20Sopenharmony_ci if (ret) 10018c2ecf20Sopenharmony_ci goto err; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xb2, 0x00); 10048c2ecf20Sopenharmony_ci if (ret) 10058c2ecf20Sopenharmony_ci goto err; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci dev->delivery_system = c->delivery_system; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci return 0; 10108c2ecf20Sopenharmony_cierr: 10118c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 10128c2ecf20Sopenharmony_ci return ret; 10138c2ecf20Sopenharmony_ci} 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cistatic int m88ds3103_init(struct dvb_frontend *fe) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = fe->demodulator_priv; 10188c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 10198c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 10208c2ecf20Sopenharmony_ci int ret, len, rem; 10218c2ecf20Sopenharmony_ci unsigned int utmp; 10228c2ecf20Sopenharmony_ci const struct firmware *firmware; 10238c2ecf20Sopenharmony_ci const char *name; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* set cold state by default */ 10288c2ecf20Sopenharmony_ci dev->warm = false; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* wake up device from sleep */ 10318c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x08, 0x01, 0x01); 10328c2ecf20Sopenharmony_ci if (ret) 10338c2ecf20Sopenharmony_ci goto err; 10348c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x04, 0x01, 0x00); 10358c2ecf20Sopenharmony_ci if (ret) 10368c2ecf20Sopenharmony_ci goto err; 10378c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x23, 0x10, 0x00); 10388c2ecf20Sopenharmony_ci if (ret) 10398c2ecf20Sopenharmony_ci goto err; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* firmware status */ 10428c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap, 0xb9, &utmp); 10438c2ecf20Sopenharmony_ci if (ret) 10448c2ecf20Sopenharmony_ci goto err; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "firmware=%02x\n", utmp); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (utmp) 10498c2ecf20Sopenharmony_ci goto warm; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* global reset, global diseqc reset, global fec reset */ 10528c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0x07, 0xe0); 10538c2ecf20Sopenharmony_ci if (ret) 10548c2ecf20Sopenharmony_ci goto err; 10558c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0x07, 0x00); 10568c2ecf20Sopenharmony_ci if (ret) 10578c2ecf20Sopenharmony_ci goto err; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci /* cold state - try to download firmware */ 10608c2ecf20Sopenharmony_ci dev_info(&client->dev, "found a '%s' in cold state\n", 10618c2ecf20Sopenharmony_ci dev->fe.ops.info.name); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) 10648c2ecf20Sopenharmony_ci name = M88DS3103B_FIRMWARE; 10658c2ecf20Sopenharmony_ci else if (dev->chip_id == M88RS6000_CHIP_ID) 10668c2ecf20Sopenharmony_ci name = M88RS6000_FIRMWARE; 10678c2ecf20Sopenharmony_ci else 10688c2ecf20Sopenharmony_ci name = M88DS3103_FIRMWARE; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci /* request the firmware, this will block and timeout */ 10718c2ecf20Sopenharmony_ci ret = request_firmware(&firmware, name, &client->dev); 10728c2ecf20Sopenharmony_ci if (ret) { 10738c2ecf20Sopenharmony_ci dev_err(&client->dev, "firmware file '%s' not found\n", name); 10748c2ecf20Sopenharmony_ci goto err; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci dev_info(&client->dev, "downloading firmware from file '%s'\n", name); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xb2, 0x01); 10808c2ecf20Sopenharmony_ci if (ret) 10818c2ecf20Sopenharmony_ci goto err_release_firmware; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci for (rem = firmware->size; rem > 0; rem -= (dev->cfg->i2c_wr_max - 1)) { 10848c2ecf20Sopenharmony_ci len = min(dev->cfg->i2c_wr_max - 1, rem); 10858c2ecf20Sopenharmony_ci ret = regmap_bulk_write(dev->regmap, 0xb0, 10868c2ecf20Sopenharmony_ci &firmware->data[firmware->size - rem], 10878c2ecf20Sopenharmony_ci len); 10888c2ecf20Sopenharmony_ci if (ret) { 10898c2ecf20Sopenharmony_ci dev_err(&client->dev, "firmware download failed %d\n", 10908c2ecf20Sopenharmony_ci ret); 10918c2ecf20Sopenharmony_ci goto err_release_firmware; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xb2, 0x00); 10968c2ecf20Sopenharmony_ci if (ret) 10978c2ecf20Sopenharmony_ci goto err_release_firmware; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci release_firmware(firmware); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap, 0xb9, &utmp); 11028c2ecf20Sopenharmony_ci if (ret) 11038c2ecf20Sopenharmony_ci goto err; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (!utmp) { 11068c2ecf20Sopenharmony_ci ret = -EINVAL; 11078c2ecf20Sopenharmony_ci dev_info(&client->dev, "firmware did not run\n"); 11088c2ecf20Sopenharmony_ci goto err; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci dev_info(&client->dev, "found a '%s' in warm state\n", 11128c2ecf20Sopenharmony_ci dev->fe.ops.info.name); 11138c2ecf20Sopenharmony_ci dev_info(&client->dev, "firmware version: %X.%X\n", 11148c2ecf20Sopenharmony_ci (utmp >> 4) & 0xf, (utmp >> 0 & 0xf)); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { 11178c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x21, 0x92); 11188c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x15, 0x6C); 11198c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x17, 0xC1); 11208c2ecf20Sopenharmony_ci m88ds3103b_dt_write(dev, 0x17, 0x81); 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ciwarm: 11238c2ecf20Sopenharmony_ci /* warm state */ 11248c2ecf20Sopenharmony_ci dev->warm = true; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci /* init stats here in order signal app which stats are supported */ 11278c2ecf20Sopenharmony_ci c->cnr.len = 1; 11288c2ecf20Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 11298c2ecf20Sopenharmony_ci c->post_bit_error.len = 1; 11308c2ecf20Sopenharmony_ci c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 11318c2ecf20Sopenharmony_ci c->post_bit_count.len = 1; 11328c2ecf20Sopenharmony_ci c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci return 0; 11358c2ecf20Sopenharmony_cierr_release_firmware: 11368c2ecf20Sopenharmony_ci release_firmware(firmware); 11378c2ecf20Sopenharmony_cierr: 11388c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 11398c2ecf20Sopenharmony_ci return ret; 11408c2ecf20Sopenharmony_ci} 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_cistatic int m88ds3103_sleep(struct dvb_frontend *fe) 11438c2ecf20Sopenharmony_ci{ 11448c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = fe->demodulator_priv; 11458c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 11468c2ecf20Sopenharmony_ci int ret; 11478c2ecf20Sopenharmony_ci unsigned int utmp; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci dev->fe_status = 0; 11528c2ecf20Sopenharmony_ci dev->delivery_system = SYS_UNDEFINED; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci /* TS Hi-Z */ 11558c2ecf20Sopenharmony_ci if (dev->chip_id == M88RS6000_CHIP_ID) 11568c2ecf20Sopenharmony_ci utmp = 0x29; 11578c2ecf20Sopenharmony_ci else 11588c2ecf20Sopenharmony_ci utmp = 0x27; 11598c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, utmp, 0x01, 0x00); 11608c2ecf20Sopenharmony_ci if (ret) 11618c2ecf20Sopenharmony_ci goto err; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci /* sleep */ 11648c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x08, 0x01, 0x00); 11658c2ecf20Sopenharmony_ci if (ret) 11668c2ecf20Sopenharmony_ci goto err; 11678c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x04, 0x01, 0x01); 11688c2ecf20Sopenharmony_ci if (ret) 11698c2ecf20Sopenharmony_ci goto err; 11708c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x23, 0x10, 0x10); 11718c2ecf20Sopenharmony_ci if (ret) 11728c2ecf20Sopenharmony_ci goto err; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci return 0; 11758c2ecf20Sopenharmony_cierr: 11768c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 11778c2ecf20Sopenharmony_ci return ret; 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_cistatic int m88ds3103_get_frontend(struct dvb_frontend *fe, 11818c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c) 11828c2ecf20Sopenharmony_ci{ 11838c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = fe->demodulator_priv; 11848c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 11858c2ecf20Sopenharmony_ci int ret; 11868c2ecf20Sopenharmony_ci u8 buf[3]; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (!dev->warm || !(dev->fe_status & FE_HAS_LOCK)) { 11918c2ecf20Sopenharmony_ci ret = 0; 11928c2ecf20Sopenharmony_ci goto err; 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci switch (c->delivery_system) { 11968c2ecf20Sopenharmony_ci case SYS_DVBS: 11978c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap, 0xe0, &buf[0], 1); 11988c2ecf20Sopenharmony_ci if (ret) 11998c2ecf20Sopenharmony_ci goto err; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap, 0xe6, &buf[1], 1); 12028c2ecf20Sopenharmony_ci if (ret) 12038c2ecf20Sopenharmony_ci goto err; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci switch ((buf[0] >> 2) & 0x01) { 12068c2ecf20Sopenharmony_ci case 0: 12078c2ecf20Sopenharmony_ci c->inversion = INVERSION_OFF; 12088c2ecf20Sopenharmony_ci break; 12098c2ecf20Sopenharmony_ci case 1: 12108c2ecf20Sopenharmony_ci c->inversion = INVERSION_ON; 12118c2ecf20Sopenharmony_ci break; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci switch ((buf[1] >> 5) & 0x07) { 12158c2ecf20Sopenharmony_ci case 0: 12168c2ecf20Sopenharmony_ci c->fec_inner = FEC_7_8; 12178c2ecf20Sopenharmony_ci break; 12188c2ecf20Sopenharmony_ci case 1: 12198c2ecf20Sopenharmony_ci c->fec_inner = FEC_5_6; 12208c2ecf20Sopenharmony_ci break; 12218c2ecf20Sopenharmony_ci case 2: 12228c2ecf20Sopenharmony_ci c->fec_inner = FEC_3_4; 12238c2ecf20Sopenharmony_ci break; 12248c2ecf20Sopenharmony_ci case 3: 12258c2ecf20Sopenharmony_ci c->fec_inner = FEC_2_3; 12268c2ecf20Sopenharmony_ci break; 12278c2ecf20Sopenharmony_ci case 4: 12288c2ecf20Sopenharmony_ci c->fec_inner = FEC_1_2; 12298c2ecf20Sopenharmony_ci break; 12308c2ecf20Sopenharmony_ci default: 12318c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid fec_inner\n"); 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci c->modulation = QPSK; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci break; 12378c2ecf20Sopenharmony_ci case SYS_DVBS2: 12388c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap, 0x7e, &buf[0], 1); 12398c2ecf20Sopenharmony_ci if (ret) 12408c2ecf20Sopenharmony_ci goto err; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap, 0x89, &buf[1], 1); 12438c2ecf20Sopenharmony_ci if (ret) 12448c2ecf20Sopenharmony_ci goto err; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap, 0xf2, &buf[2], 1); 12478c2ecf20Sopenharmony_ci if (ret) 12488c2ecf20Sopenharmony_ci goto err; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci switch ((buf[0] >> 0) & 0x0f) { 12518c2ecf20Sopenharmony_ci case 2: 12528c2ecf20Sopenharmony_ci c->fec_inner = FEC_2_5; 12538c2ecf20Sopenharmony_ci break; 12548c2ecf20Sopenharmony_ci case 3: 12558c2ecf20Sopenharmony_ci c->fec_inner = FEC_1_2; 12568c2ecf20Sopenharmony_ci break; 12578c2ecf20Sopenharmony_ci case 4: 12588c2ecf20Sopenharmony_ci c->fec_inner = FEC_3_5; 12598c2ecf20Sopenharmony_ci break; 12608c2ecf20Sopenharmony_ci case 5: 12618c2ecf20Sopenharmony_ci c->fec_inner = FEC_2_3; 12628c2ecf20Sopenharmony_ci break; 12638c2ecf20Sopenharmony_ci case 6: 12648c2ecf20Sopenharmony_ci c->fec_inner = FEC_3_4; 12658c2ecf20Sopenharmony_ci break; 12668c2ecf20Sopenharmony_ci case 7: 12678c2ecf20Sopenharmony_ci c->fec_inner = FEC_4_5; 12688c2ecf20Sopenharmony_ci break; 12698c2ecf20Sopenharmony_ci case 8: 12708c2ecf20Sopenharmony_ci c->fec_inner = FEC_5_6; 12718c2ecf20Sopenharmony_ci break; 12728c2ecf20Sopenharmony_ci case 9: 12738c2ecf20Sopenharmony_ci c->fec_inner = FEC_8_9; 12748c2ecf20Sopenharmony_ci break; 12758c2ecf20Sopenharmony_ci case 10: 12768c2ecf20Sopenharmony_ci c->fec_inner = FEC_9_10; 12778c2ecf20Sopenharmony_ci break; 12788c2ecf20Sopenharmony_ci default: 12798c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid fec_inner\n"); 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci switch ((buf[0] >> 5) & 0x01) { 12838c2ecf20Sopenharmony_ci case 0: 12848c2ecf20Sopenharmony_ci c->pilot = PILOT_OFF; 12858c2ecf20Sopenharmony_ci break; 12868c2ecf20Sopenharmony_ci case 1: 12878c2ecf20Sopenharmony_ci c->pilot = PILOT_ON; 12888c2ecf20Sopenharmony_ci break; 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci switch ((buf[0] >> 6) & 0x07) { 12928c2ecf20Sopenharmony_ci case 0: 12938c2ecf20Sopenharmony_ci c->modulation = QPSK; 12948c2ecf20Sopenharmony_ci break; 12958c2ecf20Sopenharmony_ci case 1: 12968c2ecf20Sopenharmony_ci c->modulation = PSK_8; 12978c2ecf20Sopenharmony_ci break; 12988c2ecf20Sopenharmony_ci case 2: 12998c2ecf20Sopenharmony_ci c->modulation = APSK_16; 13008c2ecf20Sopenharmony_ci break; 13018c2ecf20Sopenharmony_ci case 3: 13028c2ecf20Sopenharmony_ci c->modulation = APSK_32; 13038c2ecf20Sopenharmony_ci break; 13048c2ecf20Sopenharmony_ci default: 13058c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid modulation\n"); 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci switch ((buf[1] >> 7) & 0x01) { 13098c2ecf20Sopenharmony_ci case 0: 13108c2ecf20Sopenharmony_ci c->inversion = INVERSION_OFF; 13118c2ecf20Sopenharmony_ci break; 13128c2ecf20Sopenharmony_ci case 1: 13138c2ecf20Sopenharmony_ci c->inversion = INVERSION_ON; 13148c2ecf20Sopenharmony_ci break; 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci switch ((buf[2] >> 0) & 0x03) { 13188c2ecf20Sopenharmony_ci case 0: 13198c2ecf20Sopenharmony_ci c->rolloff = ROLLOFF_35; 13208c2ecf20Sopenharmony_ci break; 13218c2ecf20Sopenharmony_ci case 1: 13228c2ecf20Sopenharmony_ci c->rolloff = ROLLOFF_25; 13238c2ecf20Sopenharmony_ci break; 13248c2ecf20Sopenharmony_ci case 2: 13258c2ecf20Sopenharmony_ci c->rolloff = ROLLOFF_20; 13268c2ecf20Sopenharmony_ci break; 13278c2ecf20Sopenharmony_ci default: 13288c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid rolloff\n"); 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci break; 13318c2ecf20Sopenharmony_ci default: 13328c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid delivery_system\n"); 13338c2ecf20Sopenharmony_ci ret = -EINVAL; 13348c2ecf20Sopenharmony_ci goto err; 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci ret = regmap_bulk_read(dev->regmap, 0x6d, buf, 2); 13388c2ecf20Sopenharmony_ci if (ret) 13398c2ecf20Sopenharmony_ci goto err; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci c->symbol_rate = DIV_ROUND_CLOSEST_ULL((u64)(buf[1] << 8 | buf[0] << 0) * dev->mclk, 0x10000); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci return 0; 13448c2ecf20Sopenharmony_cierr: 13458c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 13468c2ecf20Sopenharmony_ci return ret; 13478c2ecf20Sopenharmony_ci} 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_cistatic int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *snr) 13508c2ecf20Sopenharmony_ci{ 13518c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) 13548c2ecf20Sopenharmony_ci *snr = div_s64(c->cnr.stat[0].svalue, 100); 13558c2ecf20Sopenharmony_ci else 13568c2ecf20Sopenharmony_ci *snr = 0; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci return 0; 13598c2ecf20Sopenharmony_ci} 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_cistatic int m88ds3103_read_ber(struct dvb_frontend *fe, u32 *ber) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = fe->demodulator_priv; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci *ber = dev->dvbv3_ber; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci return 0; 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cistatic int m88ds3103_set_tone(struct dvb_frontend *fe, 13718c2ecf20Sopenharmony_ci enum fe_sec_tone_mode fe_sec_tone_mode) 13728c2ecf20Sopenharmony_ci{ 13738c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = fe->demodulator_priv; 13748c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 13758c2ecf20Sopenharmony_ci int ret; 13768c2ecf20Sopenharmony_ci unsigned int utmp, tone, reg_a1_mask; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "fe_sec_tone_mode=%d\n", fe_sec_tone_mode); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (!dev->warm) { 13818c2ecf20Sopenharmony_ci ret = -EAGAIN; 13828c2ecf20Sopenharmony_ci goto err; 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci switch (fe_sec_tone_mode) { 13868c2ecf20Sopenharmony_ci case SEC_TONE_ON: 13878c2ecf20Sopenharmony_ci tone = 0; 13888c2ecf20Sopenharmony_ci reg_a1_mask = 0x47; 13898c2ecf20Sopenharmony_ci break; 13908c2ecf20Sopenharmony_ci case SEC_TONE_OFF: 13918c2ecf20Sopenharmony_ci tone = 1; 13928c2ecf20Sopenharmony_ci reg_a1_mask = 0x00; 13938c2ecf20Sopenharmony_ci break; 13948c2ecf20Sopenharmony_ci default: 13958c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid fe_sec_tone_mode\n"); 13968c2ecf20Sopenharmony_ci ret = -EINVAL; 13978c2ecf20Sopenharmony_ci goto err; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci utmp = tone << 7 | dev->cfg->envelope_mode << 5; 14018c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0xa2, 0xe0, utmp); 14028c2ecf20Sopenharmony_ci if (ret) 14038c2ecf20Sopenharmony_ci goto err; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci utmp = 1 << 2; 14068c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0xa1, reg_a1_mask, utmp); 14078c2ecf20Sopenharmony_ci if (ret) 14088c2ecf20Sopenharmony_ci goto err; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci return 0; 14118c2ecf20Sopenharmony_cierr: 14128c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 14138c2ecf20Sopenharmony_ci return ret; 14148c2ecf20Sopenharmony_ci} 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_cistatic int m88ds3103_set_voltage(struct dvb_frontend *fe, 14178c2ecf20Sopenharmony_ci enum fe_sec_voltage fe_sec_voltage) 14188c2ecf20Sopenharmony_ci{ 14198c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = fe->demodulator_priv; 14208c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 14218c2ecf20Sopenharmony_ci int ret; 14228c2ecf20Sopenharmony_ci unsigned int utmp; 14238c2ecf20Sopenharmony_ci bool voltage_sel, voltage_dis; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "fe_sec_voltage=%d\n", fe_sec_voltage); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci if (!dev->warm) { 14288c2ecf20Sopenharmony_ci ret = -EAGAIN; 14298c2ecf20Sopenharmony_ci goto err; 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci switch (fe_sec_voltage) { 14338c2ecf20Sopenharmony_ci case SEC_VOLTAGE_18: 14348c2ecf20Sopenharmony_ci voltage_sel = true; 14358c2ecf20Sopenharmony_ci voltage_dis = false; 14368c2ecf20Sopenharmony_ci break; 14378c2ecf20Sopenharmony_ci case SEC_VOLTAGE_13: 14388c2ecf20Sopenharmony_ci voltage_sel = false; 14398c2ecf20Sopenharmony_ci voltage_dis = false; 14408c2ecf20Sopenharmony_ci break; 14418c2ecf20Sopenharmony_ci case SEC_VOLTAGE_OFF: 14428c2ecf20Sopenharmony_ci voltage_sel = false; 14438c2ecf20Sopenharmony_ci voltage_dis = true; 14448c2ecf20Sopenharmony_ci break; 14458c2ecf20Sopenharmony_ci default: 14468c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid fe_sec_voltage\n"); 14478c2ecf20Sopenharmony_ci ret = -EINVAL; 14488c2ecf20Sopenharmony_ci goto err; 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci /* output pin polarity */ 14528c2ecf20Sopenharmony_ci voltage_sel ^= dev->cfg->lnb_hv_pol; 14538c2ecf20Sopenharmony_ci voltage_dis ^= dev->cfg->lnb_en_pol; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci utmp = voltage_dis << 1 | voltage_sel << 0; 14568c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0xa2, 0x03, utmp); 14578c2ecf20Sopenharmony_ci if (ret) 14588c2ecf20Sopenharmony_ci goto err; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci return 0; 14618c2ecf20Sopenharmony_cierr: 14628c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 14638c2ecf20Sopenharmony_ci return ret; 14648c2ecf20Sopenharmony_ci} 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_cistatic int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe, 14678c2ecf20Sopenharmony_ci struct dvb_diseqc_master_cmd *diseqc_cmd) 14688c2ecf20Sopenharmony_ci{ 14698c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = fe->demodulator_priv; 14708c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 14718c2ecf20Sopenharmony_ci int ret; 14728c2ecf20Sopenharmony_ci unsigned int utmp; 14738c2ecf20Sopenharmony_ci unsigned long timeout; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "msg=%*ph\n", 14768c2ecf20Sopenharmony_ci diseqc_cmd->msg_len, diseqc_cmd->msg); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci if (!dev->warm) { 14798c2ecf20Sopenharmony_ci ret = -EAGAIN; 14808c2ecf20Sopenharmony_ci goto err; 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 6) { 14848c2ecf20Sopenharmony_ci ret = -EINVAL; 14858c2ecf20Sopenharmony_ci goto err; 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci utmp = dev->cfg->envelope_mode << 5; 14898c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0xa2, 0xe0, utmp); 14908c2ecf20Sopenharmony_ci if (ret) 14918c2ecf20Sopenharmony_ci goto err; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci ret = regmap_bulk_write(dev->regmap, 0xa3, diseqc_cmd->msg, 14948c2ecf20Sopenharmony_ci diseqc_cmd->msg_len); 14958c2ecf20Sopenharmony_ci if (ret) 14968c2ecf20Sopenharmony_ci goto err; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xa1, 14998c2ecf20Sopenharmony_ci (diseqc_cmd->msg_len - 1) << 3 | 0x07); 15008c2ecf20Sopenharmony_ci if (ret) 15018c2ecf20Sopenharmony_ci goto err; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci /* wait DiSEqC TX ready */ 15048c2ecf20Sopenharmony_ci #define SEND_MASTER_CMD_TIMEOUT 120 15058c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(SEND_MASTER_CMD_TIMEOUT); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci /* DiSEqC message period is 13.5 ms per byte */ 15088c2ecf20Sopenharmony_ci utmp = diseqc_cmd->msg_len * 13500; 15098c2ecf20Sopenharmony_ci usleep_range(utmp - 4000, utmp); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci for (utmp = 1; !time_after(jiffies, timeout) && utmp;) { 15128c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap, 0xa1, &utmp); 15138c2ecf20Sopenharmony_ci if (ret) 15148c2ecf20Sopenharmony_ci goto err; 15158c2ecf20Sopenharmony_ci utmp = (utmp >> 6) & 0x1; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci if (utmp == 0) { 15198c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "diseqc tx took %u ms\n", 15208c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies) - 15218c2ecf20Sopenharmony_ci (jiffies_to_msecs(timeout) - SEND_MASTER_CMD_TIMEOUT)); 15228c2ecf20Sopenharmony_ci } else { 15238c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "diseqc tx timeout\n"); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0xa1, 0xc0, 0x40); 15268c2ecf20Sopenharmony_ci if (ret) 15278c2ecf20Sopenharmony_ci goto err; 15288c2ecf20Sopenharmony_ci } 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0xa2, 0xc0, 0x80); 15318c2ecf20Sopenharmony_ci if (ret) 15328c2ecf20Sopenharmony_ci goto err; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci if (utmp == 1) { 15358c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 15368c2ecf20Sopenharmony_ci goto err; 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci return 0; 15408c2ecf20Sopenharmony_cierr: 15418c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 15428c2ecf20Sopenharmony_ci return ret; 15438c2ecf20Sopenharmony_ci} 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_cistatic int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe, 15468c2ecf20Sopenharmony_ci enum fe_sec_mini_cmd fe_sec_mini_cmd) 15478c2ecf20Sopenharmony_ci{ 15488c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = fe->demodulator_priv; 15498c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 15508c2ecf20Sopenharmony_ci int ret; 15518c2ecf20Sopenharmony_ci unsigned int utmp, burst; 15528c2ecf20Sopenharmony_ci unsigned long timeout; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "fe_sec_mini_cmd=%d\n", fe_sec_mini_cmd); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci if (!dev->warm) { 15578c2ecf20Sopenharmony_ci ret = -EAGAIN; 15588c2ecf20Sopenharmony_ci goto err; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci utmp = dev->cfg->envelope_mode << 5; 15628c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0xa2, 0xe0, utmp); 15638c2ecf20Sopenharmony_ci if (ret) 15648c2ecf20Sopenharmony_ci goto err; 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci switch (fe_sec_mini_cmd) { 15678c2ecf20Sopenharmony_ci case SEC_MINI_A: 15688c2ecf20Sopenharmony_ci burst = 0x02; 15698c2ecf20Sopenharmony_ci break; 15708c2ecf20Sopenharmony_ci case SEC_MINI_B: 15718c2ecf20Sopenharmony_ci burst = 0x01; 15728c2ecf20Sopenharmony_ci break; 15738c2ecf20Sopenharmony_ci default: 15748c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "invalid fe_sec_mini_cmd\n"); 15758c2ecf20Sopenharmony_ci ret = -EINVAL; 15768c2ecf20Sopenharmony_ci goto err; 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0xa1, burst); 15808c2ecf20Sopenharmony_ci if (ret) 15818c2ecf20Sopenharmony_ci goto err; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci /* wait DiSEqC TX ready */ 15848c2ecf20Sopenharmony_ci #define SEND_BURST_TIMEOUT 40 15858c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(SEND_BURST_TIMEOUT); 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci /* DiSEqC ToneBurst period is 12.5 ms */ 15888c2ecf20Sopenharmony_ci usleep_range(8500, 12500); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci for (utmp = 1; !time_after(jiffies, timeout) && utmp;) { 15918c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap, 0xa1, &utmp); 15928c2ecf20Sopenharmony_ci if (ret) 15938c2ecf20Sopenharmony_ci goto err; 15948c2ecf20Sopenharmony_ci utmp = (utmp >> 6) & 0x1; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci if (utmp == 0) { 15988c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "diseqc tx took %u ms\n", 15998c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies) - 16008c2ecf20Sopenharmony_ci (jiffies_to_msecs(timeout) - SEND_BURST_TIMEOUT)); 16018c2ecf20Sopenharmony_ci } else { 16028c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "diseqc tx timeout\n"); 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0xa1, 0xc0, 0x40); 16058c2ecf20Sopenharmony_ci if (ret) 16068c2ecf20Sopenharmony_ci goto err; 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0xa2, 0xc0, 0x80); 16108c2ecf20Sopenharmony_ci if (ret) 16118c2ecf20Sopenharmony_ci goto err; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci if (utmp == 1) { 16148c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 16158c2ecf20Sopenharmony_ci goto err; 16168c2ecf20Sopenharmony_ci } 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci return 0; 16198c2ecf20Sopenharmony_cierr: 16208c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 16218c2ecf20Sopenharmony_ci return ret; 16228c2ecf20Sopenharmony_ci} 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_cistatic int m88ds3103_get_tune_settings(struct dvb_frontend *fe, 16258c2ecf20Sopenharmony_ci struct dvb_frontend_tune_settings *s) 16268c2ecf20Sopenharmony_ci{ 16278c2ecf20Sopenharmony_ci s->min_delay_ms = 3000; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci return 0; 16308c2ecf20Sopenharmony_ci} 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_cistatic void m88ds3103_release(struct dvb_frontend *fe) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = fe->demodulator_priv; 16358c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci i2c_unregister_device(client); 16388c2ecf20Sopenharmony_ci} 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_cistatic int m88ds3103_select(struct i2c_mux_core *muxc, u32 chan) 16418c2ecf20Sopenharmony_ci{ 16428c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = i2c_mux_priv(muxc); 16438c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 16448c2ecf20Sopenharmony_ci int ret; 16458c2ecf20Sopenharmony_ci struct i2c_msg msg = { 16468c2ecf20Sopenharmony_ci .addr = client->addr, 16478c2ecf20Sopenharmony_ci .flags = 0, 16488c2ecf20Sopenharmony_ci .len = 2, 16498c2ecf20Sopenharmony_ci .buf = "\x03\x11", 16508c2ecf20Sopenharmony_ci }; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci /* Open tuner I2C repeater for 1 xfer, closes automatically */ 16538c2ecf20Sopenharmony_ci ret = __i2c_transfer(client->adapter, &msg, 1); 16548c2ecf20Sopenharmony_ci if (ret != 1) { 16558c2ecf20Sopenharmony_ci dev_warn(&client->dev, "i2c wr failed=%d\n", ret); 16568c2ecf20Sopenharmony_ci if (ret >= 0) 16578c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 16588c2ecf20Sopenharmony_ci return ret; 16598c2ecf20Sopenharmony_ci } 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci return 0; 16628c2ecf20Sopenharmony_ci} 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci/* 16658c2ecf20Sopenharmony_ci * XXX: That is wrapper to m88ds3103_probe() via driver core in order to provide 16668c2ecf20Sopenharmony_ci * proper I2C client for legacy media attach binding. 16678c2ecf20Sopenharmony_ci * New users must use I2C client binding directly! 16688c2ecf20Sopenharmony_ci */ 16698c2ecf20Sopenharmony_cistruct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, 16708c2ecf20Sopenharmony_ci struct i2c_adapter *i2c, 16718c2ecf20Sopenharmony_ci struct i2c_adapter **tuner_i2c_adapter) 16728c2ecf20Sopenharmony_ci{ 16738c2ecf20Sopenharmony_ci struct i2c_client *client; 16748c2ecf20Sopenharmony_ci struct i2c_board_info board_info; 16758c2ecf20Sopenharmony_ci struct m88ds3103_platform_data pdata = {}; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci pdata.clk = cfg->clock; 16788c2ecf20Sopenharmony_ci pdata.i2c_wr_max = cfg->i2c_wr_max; 16798c2ecf20Sopenharmony_ci pdata.ts_mode = cfg->ts_mode; 16808c2ecf20Sopenharmony_ci pdata.ts_clk = cfg->ts_clk; 16818c2ecf20Sopenharmony_ci pdata.ts_clk_pol = cfg->ts_clk_pol; 16828c2ecf20Sopenharmony_ci pdata.spec_inv = cfg->spec_inv; 16838c2ecf20Sopenharmony_ci pdata.agc = cfg->agc; 16848c2ecf20Sopenharmony_ci pdata.agc_inv = cfg->agc_inv; 16858c2ecf20Sopenharmony_ci pdata.clk_out = cfg->clock_out; 16868c2ecf20Sopenharmony_ci pdata.envelope_mode = cfg->envelope_mode; 16878c2ecf20Sopenharmony_ci pdata.lnb_hv_pol = cfg->lnb_hv_pol; 16888c2ecf20Sopenharmony_ci pdata.lnb_en_pol = cfg->lnb_en_pol; 16898c2ecf20Sopenharmony_ci pdata.attach_in_use = true; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci memset(&board_info, 0, sizeof(board_info)); 16928c2ecf20Sopenharmony_ci strscpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); 16938c2ecf20Sopenharmony_ci board_info.addr = cfg->i2c_addr; 16948c2ecf20Sopenharmony_ci board_info.platform_data = &pdata; 16958c2ecf20Sopenharmony_ci client = i2c_new_client_device(i2c, &board_info); 16968c2ecf20Sopenharmony_ci if (!i2c_client_has_driver(client)) 16978c2ecf20Sopenharmony_ci return NULL; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci *tuner_i2c_adapter = pdata.get_i2c_adapter(client); 17008c2ecf20Sopenharmony_ci return pdata.get_dvb_frontend(client); 17018c2ecf20Sopenharmony_ci} 17028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(m88ds3103_attach); 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops m88ds3103_ops = { 17058c2ecf20Sopenharmony_ci .delsys = {SYS_DVBS, SYS_DVBS2}, 17068c2ecf20Sopenharmony_ci .info = { 17078c2ecf20Sopenharmony_ci .name = "Montage Technology M88DS3103", 17088c2ecf20Sopenharmony_ci .frequency_min_hz = 950 * MHz, 17098c2ecf20Sopenharmony_ci .frequency_max_hz = 2150 * MHz, 17108c2ecf20Sopenharmony_ci .frequency_tolerance_hz = 5 * MHz, 17118c2ecf20Sopenharmony_ci .symbol_rate_min = 1000000, 17128c2ecf20Sopenharmony_ci .symbol_rate_max = 45000000, 17138c2ecf20Sopenharmony_ci .caps = FE_CAN_INVERSION_AUTO | 17148c2ecf20Sopenharmony_ci FE_CAN_FEC_1_2 | 17158c2ecf20Sopenharmony_ci FE_CAN_FEC_2_3 | 17168c2ecf20Sopenharmony_ci FE_CAN_FEC_3_4 | 17178c2ecf20Sopenharmony_ci FE_CAN_FEC_4_5 | 17188c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | 17198c2ecf20Sopenharmony_ci FE_CAN_FEC_6_7 | 17208c2ecf20Sopenharmony_ci FE_CAN_FEC_7_8 | 17218c2ecf20Sopenharmony_ci FE_CAN_FEC_8_9 | 17228c2ecf20Sopenharmony_ci FE_CAN_FEC_AUTO | 17238c2ecf20Sopenharmony_ci FE_CAN_QPSK | 17248c2ecf20Sopenharmony_ci FE_CAN_RECOVER | 17258c2ecf20Sopenharmony_ci FE_CAN_2G_MODULATION 17268c2ecf20Sopenharmony_ci }, 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci .release = m88ds3103_release, 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci .get_tune_settings = m88ds3103_get_tune_settings, 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci .init = m88ds3103_init, 17338c2ecf20Sopenharmony_ci .sleep = m88ds3103_sleep, 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci .set_frontend = m88ds3103_set_frontend, 17368c2ecf20Sopenharmony_ci .get_frontend = m88ds3103_get_frontend, 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci .read_status = m88ds3103_read_status, 17398c2ecf20Sopenharmony_ci .read_snr = m88ds3103_read_snr, 17408c2ecf20Sopenharmony_ci .read_ber = m88ds3103_read_ber, 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci .diseqc_send_master_cmd = m88ds3103_diseqc_send_master_cmd, 17438c2ecf20Sopenharmony_ci .diseqc_send_burst = m88ds3103_diseqc_send_burst, 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci .set_tone = m88ds3103_set_tone, 17468c2ecf20Sopenharmony_ci .set_voltage = m88ds3103_set_voltage, 17478c2ecf20Sopenharmony_ci}; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_cistatic struct dvb_frontend *m88ds3103_get_dvb_frontend(struct i2c_client *client) 17508c2ecf20Sopenharmony_ci{ 17518c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = i2c_get_clientdata(client); 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci return &dev->fe; 17568c2ecf20Sopenharmony_ci} 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_cistatic struct i2c_adapter *m88ds3103_get_i2c_adapter(struct i2c_client *client) 17598c2ecf20Sopenharmony_ci{ 17608c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = i2c_get_clientdata(client); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci return dev->muxc->adapter[0]; 17658c2ecf20Sopenharmony_ci} 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_cistatic int m88ds3103_probe(struct i2c_client *client, 17688c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 17698c2ecf20Sopenharmony_ci{ 17708c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev; 17718c2ecf20Sopenharmony_ci struct m88ds3103_platform_data *pdata = client->dev.platform_data; 17728c2ecf20Sopenharmony_ci int ret; 17738c2ecf20Sopenharmony_ci unsigned int utmp; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 17768c2ecf20Sopenharmony_ci if (!dev) { 17778c2ecf20Sopenharmony_ci ret = -ENOMEM; 17788c2ecf20Sopenharmony_ci goto err; 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci dev->client = client; 17828c2ecf20Sopenharmony_ci dev->config.clock = pdata->clk; 17838c2ecf20Sopenharmony_ci dev->config.i2c_wr_max = pdata->i2c_wr_max; 17848c2ecf20Sopenharmony_ci dev->config.ts_mode = pdata->ts_mode; 17858c2ecf20Sopenharmony_ci dev->config.ts_clk = pdata->ts_clk * 1000; 17868c2ecf20Sopenharmony_ci dev->config.ts_clk_pol = pdata->ts_clk_pol; 17878c2ecf20Sopenharmony_ci dev->config.spec_inv = pdata->spec_inv; 17888c2ecf20Sopenharmony_ci dev->config.agc_inv = pdata->agc_inv; 17898c2ecf20Sopenharmony_ci dev->config.clock_out = pdata->clk_out; 17908c2ecf20Sopenharmony_ci dev->config.envelope_mode = pdata->envelope_mode; 17918c2ecf20Sopenharmony_ci dev->config.agc = pdata->agc; 17928c2ecf20Sopenharmony_ci dev->config.lnb_hv_pol = pdata->lnb_hv_pol; 17938c2ecf20Sopenharmony_ci dev->config.lnb_en_pol = pdata->lnb_en_pol; 17948c2ecf20Sopenharmony_ci dev->cfg = &dev->config; 17958c2ecf20Sopenharmony_ci /* create regmap */ 17968c2ecf20Sopenharmony_ci dev->regmap_config.reg_bits = 8, 17978c2ecf20Sopenharmony_ci dev->regmap_config.val_bits = 8, 17988c2ecf20Sopenharmony_ci dev->regmap_config.lock_arg = dev, 17998c2ecf20Sopenharmony_ci dev->regmap = devm_regmap_init_i2c(client, &dev->regmap_config); 18008c2ecf20Sopenharmony_ci if (IS_ERR(dev->regmap)) { 18018c2ecf20Sopenharmony_ci ret = PTR_ERR(dev->regmap); 18028c2ecf20Sopenharmony_ci goto err_kfree; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci /* 0x00: chip id[6:0], 0x01: chip ver[7:0], 0x02: chip ver[15:8] */ 18068c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap, 0x00, &utmp); 18078c2ecf20Sopenharmony_ci if (ret) 18088c2ecf20Sopenharmony_ci goto err_kfree; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci dev->chip_id = utmp >> 1; 18118c2ecf20Sopenharmony_ci dev->chiptype = (u8)id->driver_data; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "chip_id=%02x\n", dev->chip_id); 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci switch (dev->chip_id) { 18168c2ecf20Sopenharmony_ci case M88RS6000_CHIP_ID: 18178c2ecf20Sopenharmony_ci case M88DS3103_CHIP_ID: 18188c2ecf20Sopenharmony_ci break; 18198c2ecf20Sopenharmony_ci default: 18208c2ecf20Sopenharmony_ci ret = -ENODEV; 18218c2ecf20Sopenharmony_ci dev_err(&client->dev, "Unknown device. Chip_id=%02x\n", dev->chip_id); 18228c2ecf20Sopenharmony_ci goto err_kfree; 18238c2ecf20Sopenharmony_ci } 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci switch (dev->cfg->clock_out) { 18268c2ecf20Sopenharmony_ci case M88DS3103_CLOCK_OUT_DISABLED: 18278c2ecf20Sopenharmony_ci utmp = 0x80; 18288c2ecf20Sopenharmony_ci break; 18298c2ecf20Sopenharmony_ci case M88DS3103_CLOCK_OUT_ENABLED: 18308c2ecf20Sopenharmony_ci utmp = 0x00; 18318c2ecf20Sopenharmony_ci break; 18328c2ecf20Sopenharmony_ci case M88DS3103_CLOCK_OUT_ENABLED_DIV2: 18338c2ecf20Sopenharmony_ci utmp = 0x10; 18348c2ecf20Sopenharmony_ci break; 18358c2ecf20Sopenharmony_ci default: 18368c2ecf20Sopenharmony_ci ret = -EINVAL; 18378c2ecf20Sopenharmony_ci goto err_kfree; 18388c2ecf20Sopenharmony_ci } 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci if (!pdata->ts_clk) { 18418c2ecf20Sopenharmony_ci ret = -EINVAL; 18428c2ecf20Sopenharmony_ci goto err_kfree; 18438c2ecf20Sopenharmony_ci } 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci /* 0x29 register is defined differently for m88rs6000. */ 18468c2ecf20Sopenharmony_ci /* set internal tuner address to 0x21 */ 18478c2ecf20Sopenharmony_ci if (dev->chip_id == M88RS6000_CHIP_ID) 18488c2ecf20Sopenharmony_ci utmp = 0x00; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, 0x29, utmp); 18518c2ecf20Sopenharmony_ci if (ret) 18528c2ecf20Sopenharmony_ci goto err_kfree; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci /* sleep */ 18558c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x08, 0x01, 0x00); 18568c2ecf20Sopenharmony_ci if (ret) 18578c2ecf20Sopenharmony_ci goto err_kfree; 18588c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x04, 0x01, 0x01); 18598c2ecf20Sopenharmony_ci if (ret) 18608c2ecf20Sopenharmony_ci goto err_kfree; 18618c2ecf20Sopenharmony_ci ret = m88ds3103_update_bits(dev, 0x23, 0x10, 0x10); 18628c2ecf20Sopenharmony_ci if (ret) 18638c2ecf20Sopenharmony_ci goto err_kfree; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci /* create mux i2c adapter for tuner */ 18668c2ecf20Sopenharmony_ci dev->muxc = i2c_mux_alloc(client->adapter, &client->dev, 1, 0, 0, 18678c2ecf20Sopenharmony_ci m88ds3103_select, NULL); 18688c2ecf20Sopenharmony_ci if (!dev->muxc) { 18698c2ecf20Sopenharmony_ci ret = -ENOMEM; 18708c2ecf20Sopenharmony_ci goto err_kfree; 18718c2ecf20Sopenharmony_ci } 18728c2ecf20Sopenharmony_ci dev->muxc->priv = dev; 18738c2ecf20Sopenharmony_ci ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0); 18748c2ecf20Sopenharmony_ci if (ret) 18758c2ecf20Sopenharmony_ci goto err_kfree; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci /* create dvb_frontend */ 18788c2ecf20Sopenharmony_ci memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops)); 18798c2ecf20Sopenharmony_ci if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) 18808c2ecf20Sopenharmony_ci strscpy(dev->fe.ops.info.name, "Montage Technology M88DS3103B", 18818c2ecf20Sopenharmony_ci sizeof(dev->fe.ops.info.name)); 18828c2ecf20Sopenharmony_ci else if (dev->chip_id == M88RS6000_CHIP_ID) 18838c2ecf20Sopenharmony_ci strscpy(dev->fe.ops.info.name, "Montage Technology M88RS6000", 18848c2ecf20Sopenharmony_ci sizeof(dev->fe.ops.info.name)); 18858c2ecf20Sopenharmony_ci if (!pdata->attach_in_use) 18868c2ecf20Sopenharmony_ci dev->fe.ops.release = NULL; 18878c2ecf20Sopenharmony_ci dev->fe.demodulator_priv = dev; 18888c2ecf20Sopenharmony_ci i2c_set_clientdata(client, dev); 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci /* setup callbacks */ 18918c2ecf20Sopenharmony_ci pdata->get_dvb_frontend = m88ds3103_get_dvb_frontend; 18928c2ecf20Sopenharmony_ci pdata->get_i2c_adapter = m88ds3103_get_i2c_adapter; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { 18958c2ecf20Sopenharmony_ci /* enable i2c repeater for tuner */ 18968c2ecf20Sopenharmony_ci m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci /* get frontend address */ 18998c2ecf20Sopenharmony_ci ret = regmap_read(dev->regmap, 0x29, &utmp); 19008c2ecf20Sopenharmony_ci if (ret) 19018c2ecf20Sopenharmony_ci goto err_del_adapters; 19028c2ecf20Sopenharmony_ci dev->dt_addr = ((utmp & 0x80) == 0) ? 0x42 >> 1 : 0x40 >> 1; 19038c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "dt addr is 0x%02x\n", dev->dt_addr); 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci dev->dt_client = i2c_new_dummy_device(client->adapter, 19068c2ecf20Sopenharmony_ci dev->dt_addr); 19078c2ecf20Sopenharmony_ci if (IS_ERR(dev->dt_client)) { 19088c2ecf20Sopenharmony_ci ret = PTR_ERR(dev->dt_client); 19098c2ecf20Sopenharmony_ci goto err_del_adapters; 19108c2ecf20Sopenharmony_ci } 19118c2ecf20Sopenharmony_ci } 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci return 0; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_cierr_del_adapters: 19168c2ecf20Sopenharmony_ci i2c_mux_del_adapters(dev->muxc); 19178c2ecf20Sopenharmony_cierr_kfree: 19188c2ecf20Sopenharmony_ci kfree(dev); 19198c2ecf20Sopenharmony_cierr: 19208c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 19218c2ecf20Sopenharmony_ci return ret; 19228c2ecf20Sopenharmony_ci} 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_cistatic int m88ds3103_remove(struct i2c_client *client) 19258c2ecf20Sopenharmony_ci{ 19268c2ecf20Sopenharmony_ci struct m88ds3103_dev *dev = i2c_get_clientdata(client); 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci if (dev->dt_client) 19318c2ecf20Sopenharmony_ci i2c_unregister_device(dev->dt_client); 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci i2c_mux_del_adapters(dev->muxc); 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci kfree(dev); 19368c2ecf20Sopenharmony_ci return 0; 19378c2ecf20Sopenharmony_ci} 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_cistatic const struct i2c_device_id m88ds3103_id_table[] = { 19408c2ecf20Sopenharmony_ci {"m88ds3103", M88DS3103_CHIPTYPE_3103}, 19418c2ecf20Sopenharmony_ci {"m88rs6000", M88DS3103_CHIPTYPE_RS6000}, 19428c2ecf20Sopenharmony_ci {"m88ds3103b", M88DS3103_CHIPTYPE_3103B}, 19438c2ecf20Sopenharmony_ci {} 19448c2ecf20Sopenharmony_ci}; 19458c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, m88ds3103_id_table); 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_cistatic struct i2c_driver m88ds3103_driver = { 19488c2ecf20Sopenharmony_ci .driver = { 19498c2ecf20Sopenharmony_ci .name = "m88ds3103", 19508c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 19518c2ecf20Sopenharmony_ci }, 19528c2ecf20Sopenharmony_ci .probe = m88ds3103_probe, 19538c2ecf20Sopenharmony_ci .remove = m88ds3103_remove, 19548c2ecf20Sopenharmony_ci .id_table = m88ds3103_id_table, 19558c2ecf20Sopenharmony_ci}; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_cimodule_i2c_driver(m88ds3103_driver); 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 19608c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Montage Technology M88DS3103 DVB-S/S2 demodulator driver"); 19618c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 19628c2ecf20Sopenharmony_ciMODULE_FIRMWARE(M88DS3103_FIRMWARE); 19638c2ecf20Sopenharmony_ciMODULE_FIRMWARE(M88RS6000_FIRMWARE); 19648c2ecf20Sopenharmony_ciMODULE_FIRMWARE(M88DS3103B_FIRMWARE); 1965