18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Toshiba TC90522 Demodulator 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * NOTICE: 108c2ecf20Sopenharmony_ci * This driver is incomplete and lacks init/config of the chips, 118c2ecf20Sopenharmony_ci * as the necessary info is not disclosed. 128c2ecf20Sopenharmony_ci * It assumes that users of this driver (such as a PCI bridge of 138c2ecf20Sopenharmony_ci * DTV receiver cards) properly init and configure the chip 148c2ecf20Sopenharmony_ci * via I2C *before* calling this driver's init() function. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Currently, PT3 driver is the only one that uses this driver, 178c2ecf20Sopenharmony_ci * and contains init/config code in its firmware. 188c2ecf20Sopenharmony_ci * Thus some part of the code might be dependent on PT3 specific config. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/kernel.h> 228c2ecf20Sopenharmony_ci#include <linux/math64.h> 238c2ecf20Sopenharmony_ci#include <linux/dvb/frontend.h> 248c2ecf20Sopenharmony_ci#include <media/dvb_math.h> 258c2ecf20Sopenharmony_ci#include "tc90522.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define TC90522_I2C_THRU_REG 0xfe 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define TC90522_MODULE_IDX(addr) (((u8)(addr) & 0x02U) >> 1) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct tc90522_state { 328c2ecf20Sopenharmony_ci struct tc90522_config cfg; 338c2ecf20Sopenharmony_ci struct dvb_frontend fe; 348c2ecf20Sopenharmony_ci struct i2c_client *i2c_client; 358c2ecf20Sopenharmony_ci struct i2c_adapter tuner_i2c; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci bool lna; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistruct reg_val { 418c2ecf20Sopenharmony_ci u8 reg; 428c2ecf20Sopenharmony_ci u8 val; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int 468c2ecf20Sopenharmony_cireg_write(struct tc90522_state *state, const struct reg_val *regs, int num) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci int i, ret; 498c2ecf20Sopenharmony_ci struct i2c_msg msg; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci ret = 0; 528c2ecf20Sopenharmony_ci msg.addr = state->i2c_client->addr; 538c2ecf20Sopenharmony_ci msg.flags = 0; 548c2ecf20Sopenharmony_ci msg.len = 2; 558c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 568c2ecf20Sopenharmony_ci msg.buf = (u8 *)®s[i]; 578c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c_client->adapter, &msg, 1); 588c2ecf20Sopenharmony_ci if (ret == 0) 598c2ecf20Sopenharmony_ci ret = -EIO; 608c2ecf20Sopenharmony_ci if (ret < 0) 618c2ecf20Sopenharmony_ci return ret; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci return 0; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int reg_read(struct tc90522_state *state, u8 reg, u8 *val, u8 len) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct i2c_msg msgs[2] = { 698c2ecf20Sopenharmony_ci { 708c2ecf20Sopenharmony_ci .addr = state->i2c_client->addr, 718c2ecf20Sopenharmony_ci .flags = 0, 728c2ecf20Sopenharmony_ci .buf = ®, 738c2ecf20Sopenharmony_ci .len = 1, 748c2ecf20Sopenharmony_ci }, 758c2ecf20Sopenharmony_ci { 768c2ecf20Sopenharmony_ci .addr = state->i2c_client->addr, 778c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 788c2ecf20Sopenharmony_ci .buf = val, 798c2ecf20Sopenharmony_ci .len = len, 808c2ecf20Sopenharmony_ci }, 818c2ecf20Sopenharmony_ci }; 828c2ecf20Sopenharmony_ci int ret; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c_client->adapter, msgs, ARRAY_SIZE(msgs)); 858c2ecf20Sopenharmony_ci if (ret == ARRAY_SIZE(msgs)) 868c2ecf20Sopenharmony_ci ret = 0; 878c2ecf20Sopenharmony_ci else if (ret >= 0) 888c2ecf20Sopenharmony_ci ret = -EIO; 898c2ecf20Sopenharmony_ci return ret; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic struct tc90522_state *cfg_to_state(struct tc90522_config *c) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci return container_of(c, struct tc90522_state, cfg); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int tc90522s_set_tsid(struct dvb_frontend *fe) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct reg_val set_tsid[] = { 1018c2ecf20Sopenharmony_ci { 0x8f, 00 }, 1028c2ecf20Sopenharmony_ci { 0x90, 00 } 1038c2ecf20Sopenharmony_ci }; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci set_tsid[0].val = (fe->dtv_property_cache.stream_id & 0xff00) >> 8; 1068c2ecf20Sopenharmony_ci set_tsid[1].val = fe->dtv_property_cache.stream_id & 0xff; 1078c2ecf20Sopenharmony_ci return reg_write(fe->demodulator_priv, set_tsid, ARRAY_SIZE(set_tsid)); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int tc90522t_set_layers(struct dvb_frontend *fe) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct reg_val rv; 1138c2ecf20Sopenharmony_ci u8 laysel; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci laysel = ~fe->dtv_property_cache.isdbt_layer_enabled & 0x07; 1168c2ecf20Sopenharmony_ci laysel = (laysel & 0x01) << 2 | (laysel & 0x02) | (laysel & 0x04) >> 2; 1178c2ecf20Sopenharmony_ci rv.reg = 0x71; 1188c2ecf20Sopenharmony_ci rv.val = laysel; 1198c2ecf20Sopenharmony_ci return reg_write(fe->demodulator_priv, &rv, 1); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* frontend ops */ 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int tc90522s_read_status(struct dvb_frontend *fe, enum fe_status *status) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct tc90522_state *state; 1278c2ecf20Sopenharmony_ci int ret; 1288c2ecf20Sopenharmony_ci u8 reg; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci state = fe->demodulator_priv; 1318c2ecf20Sopenharmony_ci ret = reg_read(state, 0xc3, ®, 1); 1328c2ecf20Sopenharmony_ci if (ret < 0) 1338c2ecf20Sopenharmony_ci return ret; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci *status = 0; 1368c2ecf20Sopenharmony_ci if (reg & 0x80) /* input level under min ? */ 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci *status |= FE_HAS_SIGNAL; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (reg & 0x60) /* carrier? */ 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci *status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (reg & 0x10) 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci if (reg_read(state, 0xc5, ®, 1) < 0 || !(reg & 0x03)) 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci *status |= FE_HAS_LOCK; 1498c2ecf20Sopenharmony_ci return 0; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic int tc90522t_read_status(struct dvb_frontend *fe, enum fe_status *status) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct tc90522_state *state; 1558c2ecf20Sopenharmony_ci int ret; 1568c2ecf20Sopenharmony_ci u8 reg; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci state = fe->demodulator_priv; 1598c2ecf20Sopenharmony_ci ret = reg_read(state, 0x96, ®, 1); 1608c2ecf20Sopenharmony_ci if (ret < 0) 1618c2ecf20Sopenharmony_ci return ret; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci *status = 0; 1648c2ecf20Sopenharmony_ci if (reg & 0xe0) { 1658c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI 1668c2ecf20Sopenharmony_ci | FE_HAS_SYNC | FE_HAS_LOCK; 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci ret = reg_read(state, 0x80, ®, 1); 1718c2ecf20Sopenharmony_ci if (ret < 0) 1728c2ecf20Sopenharmony_ci return ret; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (reg & 0xf0) 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ci *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (reg & 0x0c) 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci *status |= FE_HAS_SYNC | FE_HAS_VITERBI; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (reg & 0x02) 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci *status |= FE_HAS_LOCK; 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic const enum fe_code_rate fec_conv_sat[] = { 1898c2ecf20Sopenharmony_ci FEC_NONE, /* unused */ 1908c2ecf20Sopenharmony_ci FEC_1_2, /* for BPSK */ 1918c2ecf20Sopenharmony_ci FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, /* for QPSK */ 1928c2ecf20Sopenharmony_ci FEC_2_3, /* for 8PSK. (trellis code) */ 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int tc90522s_get_frontend(struct dvb_frontend *fe, 1968c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct tc90522_state *state; 1998c2ecf20Sopenharmony_ci struct dtv_fe_stats *stats; 2008c2ecf20Sopenharmony_ci int ret, i; 2018c2ecf20Sopenharmony_ci int layers; 2028c2ecf20Sopenharmony_ci u8 val[10]; 2038c2ecf20Sopenharmony_ci u32 cndat; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci state = fe->demodulator_priv; 2068c2ecf20Sopenharmony_ci c->delivery_system = SYS_ISDBS; 2078c2ecf20Sopenharmony_ci c->symbol_rate = 28860000; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci layers = 0; 2108c2ecf20Sopenharmony_ci ret = reg_read(state, 0xe6, val, 5); 2118c2ecf20Sopenharmony_ci if (ret == 0) { 2128c2ecf20Sopenharmony_ci u8 v; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci c->stream_id = val[0] << 8 | val[1]; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* high/single layer */ 2178c2ecf20Sopenharmony_ci v = (val[2] & 0x70) >> 4; 2188c2ecf20Sopenharmony_ci c->modulation = (v == 7) ? PSK_8 : QPSK; 2198c2ecf20Sopenharmony_ci c->fec_inner = fec_conv_sat[v]; 2208c2ecf20Sopenharmony_ci c->layer[0].fec = c->fec_inner; 2218c2ecf20Sopenharmony_ci c->layer[0].modulation = c->modulation; 2228c2ecf20Sopenharmony_ci c->layer[0].segment_count = val[3] & 0x3f; /* slots */ 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* low layer */ 2258c2ecf20Sopenharmony_ci v = (val[2] & 0x07); 2268c2ecf20Sopenharmony_ci c->layer[1].fec = fec_conv_sat[v]; 2278c2ecf20Sopenharmony_ci if (v == 0) /* no low layer */ 2288c2ecf20Sopenharmony_ci c->layer[1].segment_count = 0; 2298c2ecf20Sopenharmony_ci else 2308c2ecf20Sopenharmony_ci c->layer[1].segment_count = val[4] & 0x3f; /* slots */ 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * actually, BPSK if v==1, but not defined in 2338c2ecf20Sopenharmony_ci * enum fe_modulation 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci c->layer[1].modulation = QPSK; 2368c2ecf20Sopenharmony_ci layers = (v > 0) ? 2 : 1; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* statistics */ 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci stats = &c->strength; 2428c2ecf20Sopenharmony_ci stats->len = 0; 2438c2ecf20Sopenharmony_ci /* let the connected tuner set RSSI property cache */ 2448c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.get_rf_strength) { 2458c2ecf20Sopenharmony_ci u16 dummy; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci fe->ops.tuner_ops.get_rf_strength(fe, &dummy); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci stats = &c->cnr; 2518c2ecf20Sopenharmony_ci stats->len = 1; 2528c2ecf20Sopenharmony_ci stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE; 2538c2ecf20Sopenharmony_ci cndat = 0; 2548c2ecf20Sopenharmony_ci ret = reg_read(state, 0xbc, val, 2); 2558c2ecf20Sopenharmony_ci if (ret == 0) 2568c2ecf20Sopenharmony_ci cndat = val[0] << 8 | val[1]; 2578c2ecf20Sopenharmony_ci if (cndat >= 3000) { 2588c2ecf20Sopenharmony_ci u32 p, p4; 2598c2ecf20Sopenharmony_ci s64 cn; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci cndat -= 3000; /* cndat: 4.12 fixed point float */ 2628c2ecf20Sopenharmony_ci /* 2638c2ecf20Sopenharmony_ci * cnr[mdB] = -1634.6 * P^5 + 14341 * P^4 - 50259 * P^3 2648c2ecf20Sopenharmony_ci * + 88977 * P^2 - 89565 * P + 58857 2658c2ecf20Sopenharmony_ci * (P = sqrt(cndat) / 64) 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci /* p := sqrt(cndat) << 8 = P << 14, 2.14 fixed point float */ 2688c2ecf20Sopenharmony_ci /* cn = cnr << 3 */ 2698c2ecf20Sopenharmony_ci p = int_sqrt(cndat << 16); 2708c2ecf20Sopenharmony_ci p4 = cndat * cndat; 2718c2ecf20Sopenharmony_ci cn = div64_s64(-16346LL * p4 * p, 10) >> 35; 2728c2ecf20Sopenharmony_ci cn += (14341LL * p4) >> 21; 2738c2ecf20Sopenharmony_ci cn -= (50259LL * cndat * p) >> 23; 2748c2ecf20Sopenharmony_ci cn += (88977LL * cndat) >> 9; 2758c2ecf20Sopenharmony_ci cn -= (89565LL * p) >> 11; 2768c2ecf20Sopenharmony_ci cn += 58857 << 3; 2778c2ecf20Sopenharmony_ci stats->stat[0].svalue = cn >> 3; 2788c2ecf20Sopenharmony_ci stats->stat[0].scale = FE_SCALE_DECIBEL; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* per-layer post viterbi BER (or PER? config dependent?) */ 2828c2ecf20Sopenharmony_ci stats = &c->post_bit_error; 2838c2ecf20Sopenharmony_ci memset(stats, 0, sizeof(*stats)); 2848c2ecf20Sopenharmony_ci stats->len = layers; 2858c2ecf20Sopenharmony_ci ret = reg_read(state, 0xeb, val, 10); 2868c2ecf20Sopenharmony_ci if (ret < 0) 2878c2ecf20Sopenharmony_ci for (i = 0; i < layers; i++) 2888c2ecf20Sopenharmony_ci stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; 2898c2ecf20Sopenharmony_ci else { 2908c2ecf20Sopenharmony_ci for (i = 0; i < layers; i++) { 2918c2ecf20Sopenharmony_ci stats->stat[i].scale = FE_SCALE_COUNTER; 2928c2ecf20Sopenharmony_ci stats->stat[i].uvalue = val[i * 5] << 16 2938c2ecf20Sopenharmony_ci | val[i * 5 + 1] << 8 | val[i * 5 + 2]; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci stats = &c->post_bit_count; 2978c2ecf20Sopenharmony_ci memset(stats, 0, sizeof(*stats)); 2988c2ecf20Sopenharmony_ci stats->len = layers; 2998c2ecf20Sopenharmony_ci if (ret < 0) 3008c2ecf20Sopenharmony_ci for (i = 0; i < layers; i++) 3018c2ecf20Sopenharmony_ci stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; 3028c2ecf20Sopenharmony_ci else { 3038c2ecf20Sopenharmony_ci for (i = 0; i < layers; i++) { 3048c2ecf20Sopenharmony_ci stats->stat[i].scale = FE_SCALE_COUNTER; 3058c2ecf20Sopenharmony_ci stats->stat[i].uvalue = 3068c2ecf20Sopenharmony_ci val[i * 5 + 3] << 8 | val[i * 5 + 4]; 3078c2ecf20Sopenharmony_ci stats->stat[i].uvalue *= 204 * 8; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic const enum fe_transmit_mode tm_conv[] = { 3168c2ecf20Sopenharmony_ci TRANSMISSION_MODE_2K, 3178c2ecf20Sopenharmony_ci TRANSMISSION_MODE_4K, 3188c2ecf20Sopenharmony_ci TRANSMISSION_MODE_8K, 3198c2ecf20Sopenharmony_ci 0 3208c2ecf20Sopenharmony_ci}; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic const enum fe_code_rate fec_conv_ter[] = { 3238c2ecf20Sopenharmony_ci FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, 0, 0, 0 3248c2ecf20Sopenharmony_ci}; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic const enum fe_modulation mod_conv[] = { 3278c2ecf20Sopenharmony_ci DQPSK, QPSK, QAM_16, QAM_64, 0, 0, 0, 0 3288c2ecf20Sopenharmony_ci}; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int tc90522t_get_frontend(struct dvb_frontend *fe, 3318c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct tc90522_state *state; 3348c2ecf20Sopenharmony_ci struct dtv_fe_stats *stats; 3358c2ecf20Sopenharmony_ci int ret, i; 3368c2ecf20Sopenharmony_ci int layers; 3378c2ecf20Sopenharmony_ci u8 val[15], mode; 3388c2ecf20Sopenharmony_ci u32 cndat; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci state = fe->demodulator_priv; 3418c2ecf20Sopenharmony_ci c->delivery_system = SYS_ISDBT; 3428c2ecf20Sopenharmony_ci c->bandwidth_hz = 6000000; 3438c2ecf20Sopenharmony_ci mode = 1; 3448c2ecf20Sopenharmony_ci ret = reg_read(state, 0xb0, val, 1); 3458c2ecf20Sopenharmony_ci if (ret == 0) { 3468c2ecf20Sopenharmony_ci mode = (val[0] & 0xc0) >> 6; 3478c2ecf20Sopenharmony_ci c->transmission_mode = tm_conv[mode]; 3488c2ecf20Sopenharmony_ci c->guard_interval = (val[0] & 0x30) >> 4; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci ret = reg_read(state, 0xb2, val, 6); 3528c2ecf20Sopenharmony_ci layers = 0; 3538c2ecf20Sopenharmony_ci if (ret == 0) { 3548c2ecf20Sopenharmony_ci u8 v; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci c->isdbt_partial_reception = val[0] & 0x01; 3578c2ecf20Sopenharmony_ci c->isdbt_sb_mode = (val[0] & 0xc0) == 0x40; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* layer A */ 3608c2ecf20Sopenharmony_ci v = (val[2] & 0x78) >> 3; 3618c2ecf20Sopenharmony_ci if (v == 0x0f) 3628c2ecf20Sopenharmony_ci c->layer[0].segment_count = 0; 3638c2ecf20Sopenharmony_ci else { 3648c2ecf20Sopenharmony_ci layers++; 3658c2ecf20Sopenharmony_ci c->layer[0].segment_count = v; 3668c2ecf20Sopenharmony_ci c->layer[0].fec = fec_conv_ter[(val[1] & 0x1c) >> 2]; 3678c2ecf20Sopenharmony_ci c->layer[0].modulation = mod_conv[(val[1] & 0xe0) >> 5]; 3688c2ecf20Sopenharmony_ci v = (val[1] & 0x03) << 1 | (val[2] & 0x80) >> 7; 3698c2ecf20Sopenharmony_ci c->layer[0].interleaving = v; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* layer B */ 3738c2ecf20Sopenharmony_ci v = (val[3] & 0x03) << 2 | (val[4] & 0xc0) >> 6; 3748c2ecf20Sopenharmony_ci if (v == 0x0f) 3758c2ecf20Sopenharmony_ci c->layer[1].segment_count = 0; 3768c2ecf20Sopenharmony_ci else { 3778c2ecf20Sopenharmony_ci layers++; 3788c2ecf20Sopenharmony_ci c->layer[1].segment_count = v; 3798c2ecf20Sopenharmony_ci c->layer[1].fec = fec_conv_ter[(val[3] & 0xe0) >> 5]; 3808c2ecf20Sopenharmony_ci c->layer[1].modulation = mod_conv[(val[2] & 0x07)]; 3818c2ecf20Sopenharmony_ci c->layer[1].interleaving = (val[3] & 0x1c) >> 2; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* layer C */ 3858c2ecf20Sopenharmony_ci v = (val[5] & 0x1e) >> 1; 3868c2ecf20Sopenharmony_ci if (v == 0x0f) 3878c2ecf20Sopenharmony_ci c->layer[2].segment_count = 0; 3888c2ecf20Sopenharmony_ci else { 3898c2ecf20Sopenharmony_ci layers++; 3908c2ecf20Sopenharmony_ci c->layer[2].segment_count = v; 3918c2ecf20Sopenharmony_ci c->layer[2].fec = fec_conv_ter[(val[4] & 0x07)]; 3928c2ecf20Sopenharmony_ci c->layer[2].modulation = mod_conv[(val[4] & 0x38) >> 3]; 3938c2ecf20Sopenharmony_ci c->layer[2].interleaving = (val[5] & 0xe0) >> 5; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* statistics */ 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci stats = &c->strength; 4008c2ecf20Sopenharmony_ci stats->len = 0; 4018c2ecf20Sopenharmony_ci /* let the connected tuner set RSSI property cache */ 4028c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.get_rf_strength) { 4038c2ecf20Sopenharmony_ci u16 dummy; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci fe->ops.tuner_ops.get_rf_strength(fe, &dummy); 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci stats = &c->cnr; 4098c2ecf20Sopenharmony_ci stats->len = 1; 4108c2ecf20Sopenharmony_ci stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE; 4118c2ecf20Sopenharmony_ci cndat = 0; 4128c2ecf20Sopenharmony_ci ret = reg_read(state, 0x8b, val, 3); 4138c2ecf20Sopenharmony_ci if (ret == 0) 4148c2ecf20Sopenharmony_ci cndat = val[0] << 16 | val[1] << 8 | val[2]; 4158c2ecf20Sopenharmony_ci if (cndat != 0) { 4168c2ecf20Sopenharmony_ci u32 p, tmp; 4178c2ecf20Sopenharmony_ci s64 cn; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* 4208c2ecf20Sopenharmony_ci * cnr[mdB] = 0.024 P^4 - 1.6 P^3 + 39.8 P^2 + 549.1 P + 3096.5 4218c2ecf20Sopenharmony_ci * (P = 10log10(5505024/cndat)) 4228c2ecf20Sopenharmony_ci */ 4238c2ecf20Sopenharmony_ci /* cn = cnr << 3 (61.3 fixed point float */ 4248c2ecf20Sopenharmony_ci /* p = 10log10(5505024/cndat) << 24 (8.24 fixed point float)*/ 4258c2ecf20Sopenharmony_ci p = intlog10(5505024) - intlog10(cndat); 4268c2ecf20Sopenharmony_ci p *= 10; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci cn = 24772; 4298c2ecf20Sopenharmony_ci cn += div64_s64(43827LL * p, 10) >> 24; 4308c2ecf20Sopenharmony_ci tmp = p >> 8; 4318c2ecf20Sopenharmony_ci cn += div64_s64(3184LL * tmp * tmp, 10) >> 32; 4328c2ecf20Sopenharmony_ci tmp = p >> 13; 4338c2ecf20Sopenharmony_ci cn -= div64_s64(128LL * tmp * tmp * tmp, 10) >> 33; 4348c2ecf20Sopenharmony_ci tmp = p >> 18; 4358c2ecf20Sopenharmony_ci cn += div64_s64(192LL * tmp * tmp * tmp * tmp, 1000) >> 24; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci stats->stat[0].svalue = cn >> 3; 4388c2ecf20Sopenharmony_ci stats->stat[0].scale = FE_SCALE_DECIBEL; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* per-layer post viterbi BER (or PER? config dependent?) */ 4428c2ecf20Sopenharmony_ci stats = &c->post_bit_error; 4438c2ecf20Sopenharmony_ci memset(stats, 0, sizeof(*stats)); 4448c2ecf20Sopenharmony_ci stats->len = layers; 4458c2ecf20Sopenharmony_ci ret = reg_read(state, 0x9d, val, 15); 4468c2ecf20Sopenharmony_ci if (ret < 0) 4478c2ecf20Sopenharmony_ci for (i = 0; i < layers; i++) 4488c2ecf20Sopenharmony_ci stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; 4498c2ecf20Sopenharmony_ci else { 4508c2ecf20Sopenharmony_ci for (i = 0; i < layers; i++) { 4518c2ecf20Sopenharmony_ci stats->stat[i].scale = FE_SCALE_COUNTER; 4528c2ecf20Sopenharmony_ci stats->stat[i].uvalue = val[i * 3] << 16 4538c2ecf20Sopenharmony_ci | val[i * 3 + 1] << 8 | val[i * 3 + 2]; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci stats = &c->post_bit_count; 4578c2ecf20Sopenharmony_ci memset(stats, 0, sizeof(*stats)); 4588c2ecf20Sopenharmony_ci stats->len = layers; 4598c2ecf20Sopenharmony_ci if (ret < 0) 4608c2ecf20Sopenharmony_ci for (i = 0; i < layers; i++) 4618c2ecf20Sopenharmony_ci stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; 4628c2ecf20Sopenharmony_ci else { 4638c2ecf20Sopenharmony_ci for (i = 0; i < layers; i++) { 4648c2ecf20Sopenharmony_ci stats->stat[i].scale = FE_SCALE_COUNTER; 4658c2ecf20Sopenharmony_ci stats->stat[i].uvalue = 4668c2ecf20Sopenharmony_ci val[9 + i * 2] << 8 | val[9 + i * 2 + 1]; 4678c2ecf20Sopenharmony_ci stats->stat[i].uvalue *= 204 * 8; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return 0; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic const struct reg_val reset_sat = { 0x03, 0x01 }; 4758c2ecf20Sopenharmony_cistatic const struct reg_val reset_ter = { 0x01, 0x40 }; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic int tc90522_set_frontend(struct dvb_frontend *fe) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct tc90522_state *state; 4808c2ecf20Sopenharmony_ci int ret; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci state = fe->demodulator_priv; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params) 4858c2ecf20Sopenharmony_ci ret = fe->ops.tuner_ops.set_params(fe); 4868c2ecf20Sopenharmony_ci else 4878c2ecf20Sopenharmony_ci ret = -ENODEV; 4888c2ecf20Sopenharmony_ci if (ret < 0) 4898c2ecf20Sopenharmony_ci goto failed; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (fe->ops.delsys[0] == SYS_ISDBS) { 4928c2ecf20Sopenharmony_ci ret = tc90522s_set_tsid(fe); 4938c2ecf20Sopenharmony_ci if (ret < 0) 4948c2ecf20Sopenharmony_ci goto failed; 4958c2ecf20Sopenharmony_ci ret = reg_write(state, &reset_sat, 1); 4968c2ecf20Sopenharmony_ci } else { 4978c2ecf20Sopenharmony_ci ret = tc90522t_set_layers(fe); 4988c2ecf20Sopenharmony_ci if (ret < 0) 4998c2ecf20Sopenharmony_ci goto failed; 5008c2ecf20Sopenharmony_ci ret = reg_write(state, &reset_ter, 1); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci if (ret < 0) 5038c2ecf20Sopenharmony_ci goto failed; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return 0; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cifailed: 5088c2ecf20Sopenharmony_ci dev_warn(&state->tuner_i2c.dev, "(%s) failed. [adap%d-fe%d]\n", 5098c2ecf20Sopenharmony_ci __func__, fe->dvb->num, fe->id); 5108c2ecf20Sopenharmony_ci return ret; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic int tc90522_get_tune_settings(struct dvb_frontend *fe, 5148c2ecf20Sopenharmony_ci struct dvb_frontend_tune_settings *settings) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci if (fe->ops.delsys[0] == SYS_ISDBS) { 5178c2ecf20Sopenharmony_ci settings->min_delay_ms = 250; 5188c2ecf20Sopenharmony_ci settings->step_size = 1000; 5198c2ecf20Sopenharmony_ci settings->max_drift = settings->step_size * 2; 5208c2ecf20Sopenharmony_ci } else { 5218c2ecf20Sopenharmony_ci settings->min_delay_ms = 400; 5228c2ecf20Sopenharmony_ci settings->step_size = 142857; 5238c2ecf20Sopenharmony_ci settings->max_drift = settings->step_size; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci return 0; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic int tc90522_set_if_agc(struct dvb_frontend *fe, bool on) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci struct reg_val agc_sat[] = { 5318c2ecf20Sopenharmony_ci { 0x0a, 0x00 }, 5328c2ecf20Sopenharmony_ci { 0x10, 0x30 }, 5338c2ecf20Sopenharmony_ci { 0x11, 0x00 }, 5348c2ecf20Sopenharmony_ci { 0x03, 0x01 }, 5358c2ecf20Sopenharmony_ci }; 5368c2ecf20Sopenharmony_ci struct reg_val agc_ter[] = { 5378c2ecf20Sopenharmony_ci { 0x25, 0x00 }, 5388c2ecf20Sopenharmony_ci { 0x23, 0x4c }, 5398c2ecf20Sopenharmony_ci { 0x01, 0x40 }, 5408c2ecf20Sopenharmony_ci }; 5418c2ecf20Sopenharmony_ci struct tc90522_state *state; 5428c2ecf20Sopenharmony_ci struct reg_val *rv; 5438c2ecf20Sopenharmony_ci int num; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci state = fe->demodulator_priv; 5468c2ecf20Sopenharmony_ci if (fe->ops.delsys[0] == SYS_ISDBS) { 5478c2ecf20Sopenharmony_ci agc_sat[0].val = on ? 0xff : 0x00; 5488c2ecf20Sopenharmony_ci agc_sat[1].val |= 0x80; 5498c2ecf20Sopenharmony_ci agc_sat[1].val |= on ? 0x01 : 0x00; 5508c2ecf20Sopenharmony_ci agc_sat[2].val |= on ? 0x40 : 0x00; 5518c2ecf20Sopenharmony_ci rv = agc_sat; 5528c2ecf20Sopenharmony_ci num = ARRAY_SIZE(agc_sat); 5538c2ecf20Sopenharmony_ci } else { 5548c2ecf20Sopenharmony_ci agc_ter[0].val = on ? 0x40 : 0x00; 5558c2ecf20Sopenharmony_ci agc_ter[1].val |= on ? 0x00 : 0x01; 5568c2ecf20Sopenharmony_ci rv = agc_ter; 5578c2ecf20Sopenharmony_ci num = ARRAY_SIZE(agc_ter); 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci return reg_write(state, rv, num); 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic const struct reg_val sleep_sat = { 0x17, 0x01 }; 5638c2ecf20Sopenharmony_cistatic const struct reg_val sleep_ter = { 0x03, 0x90 }; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic int tc90522_sleep(struct dvb_frontend *fe) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct tc90522_state *state; 5688c2ecf20Sopenharmony_ci int ret; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci state = fe->demodulator_priv; 5718c2ecf20Sopenharmony_ci if (fe->ops.delsys[0] == SYS_ISDBS) 5728c2ecf20Sopenharmony_ci ret = reg_write(state, &sleep_sat, 1); 5738c2ecf20Sopenharmony_ci else { 5748c2ecf20Sopenharmony_ci ret = reg_write(state, &sleep_ter, 1); 5758c2ecf20Sopenharmony_ci if (ret == 0 && fe->ops.set_lna && 5768c2ecf20Sopenharmony_ci fe->dtv_property_cache.lna == LNA_AUTO) { 5778c2ecf20Sopenharmony_ci fe->dtv_property_cache.lna = 0; 5788c2ecf20Sopenharmony_ci ret = fe->ops.set_lna(fe); 5798c2ecf20Sopenharmony_ci fe->dtv_property_cache.lna = LNA_AUTO; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci if (ret < 0) 5838c2ecf20Sopenharmony_ci dev_warn(&state->tuner_i2c.dev, 5848c2ecf20Sopenharmony_ci "(%s) failed. [adap%d-fe%d]\n", 5858c2ecf20Sopenharmony_ci __func__, fe->dvb->num, fe->id); 5868c2ecf20Sopenharmony_ci return ret; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic const struct reg_val wakeup_sat = { 0x17, 0x00 }; 5908c2ecf20Sopenharmony_cistatic const struct reg_val wakeup_ter = { 0x03, 0x80 }; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic int tc90522_init(struct dvb_frontend *fe) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci struct tc90522_state *state; 5958c2ecf20Sopenharmony_ci int ret; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* 5988c2ecf20Sopenharmony_ci * Because the init sequence is not public, 5998c2ecf20Sopenharmony_ci * the parent device/driver should have init'ed the device before. 6008c2ecf20Sopenharmony_ci * just wake up the device here. 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci state = fe->demodulator_priv; 6048c2ecf20Sopenharmony_ci if (fe->ops.delsys[0] == SYS_ISDBS) 6058c2ecf20Sopenharmony_ci ret = reg_write(state, &wakeup_sat, 1); 6068c2ecf20Sopenharmony_ci else { 6078c2ecf20Sopenharmony_ci ret = reg_write(state, &wakeup_ter, 1); 6088c2ecf20Sopenharmony_ci if (ret == 0 && fe->ops.set_lna && 6098c2ecf20Sopenharmony_ci fe->dtv_property_cache.lna == LNA_AUTO) { 6108c2ecf20Sopenharmony_ci fe->dtv_property_cache.lna = 1; 6118c2ecf20Sopenharmony_ci ret = fe->ops.set_lna(fe); 6128c2ecf20Sopenharmony_ci fe->dtv_property_cache.lna = LNA_AUTO; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci if (ret < 0) { 6168c2ecf20Sopenharmony_ci dev_warn(&state->tuner_i2c.dev, 6178c2ecf20Sopenharmony_ci "(%s) failed. [adap%d-fe%d]\n", 6188c2ecf20Sopenharmony_ci __func__, fe->dvb->num, fe->id); 6198c2ecf20Sopenharmony_ci return ret; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* prefer 'all-layers' to 'none' as a default */ 6238c2ecf20Sopenharmony_ci if (fe->dtv_property_cache.isdbt_layer_enabled == 0) 6248c2ecf20Sopenharmony_ci fe->dtv_property_cache.isdbt_layer_enabled = 7; 6258c2ecf20Sopenharmony_ci return tc90522_set_if_agc(fe, true); 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci/* 6308c2ecf20Sopenharmony_ci * tuner I2C adapter functions 6318c2ecf20Sopenharmony_ci */ 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int 6348c2ecf20Sopenharmony_citc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct tc90522_state *state; 6378c2ecf20Sopenharmony_ci struct i2c_msg *new_msgs; 6388c2ecf20Sopenharmony_ci int i, j; 6398c2ecf20Sopenharmony_ci int ret, rd_num; 6408c2ecf20Sopenharmony_ci u8 wbuf[256]; 6418c2ecf20Sopenharmony_ci u8 *p, *bufend; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (num <= 0) 6448c2ecf20Sopenharmony_ci return -EINVAL; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci rd_num = 0; 6478c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) 6488c2ecf20Sopenharmony_ci if (msgs[i].flags & I2C_M_RD) 6498c2ecf20Sopenharmony_ci rd_num++; 6508c2ecf20Sopenharmony_ci new_msgs = kmalloc_array(num + rd_num, sizeof(*new_msgs), GFP_KERNEL); 6518c2ecf20Sopenharmony_ci if (!new_msgs) 6528c2ecf20Sopenharmony_ci return -ENOMEM; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci state = i2c_get_adapdata(adap); 6558c2ecf20Sopenharmony_ci p = wbuf; 6568c2ecf20Sopenharmony_ci bufend = wbuf + sizeof(wbuf); 6578c2ecf20Sopenharmony_ci for (i = 0, j = 0; i < num; i++, j++) { 6588c2ecf20Sopenharmony_ci new_msgs[j].addr = state->i2c_client->addr; 6598c2ecf20Sopenharmony_ci new_msgs[j].flags = msgs[i].flags; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (msgs[i].flags & I2C_M_RD) { 6628c2ecf20Sopenharmony_ci new_msgs[j].flags &= ~I2C_M_RD; 6638c2ecf20Sopenharmony_ci if (p + 2 > bufend) 6648c2ecf20Sopenharmony_ci break; 6658c2ecf20Sopenharmony_ci p[0] = TC90522_I2C_THRU_REG; 6668c2ecf20Sopenharmony_ci p[1] = msgs[i].addr << 1 | 0x01; 6678c2ecf20Sopenharmony_ci new_msgs[j].buf = p; 6688c2ecf20Sopenharmony_ci new_msgs[j].len = 2; 6698c2ecf20Sopenharmony_ci p += 2; 6708c2ecf20Sopenharmony_ci j++; 6718c2ecf20Sopenharmony_ci new_msgs[j].addr = state->i2c_client->addr; 6728c2ecf20Sopenharmony_ci new_msgs[j].flags = msgs[i].flags; 6738c2ecf20Sopenharmony_ci new_msgs[j].buf = msgs[i].buf; 6748c2ecf20Sopenharmony_ci new_msgs[j].len = msgs[i].len; 6758c2ecf20Sopenharmony_ci continue; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (p + msgs[i].len + 2 > bufend) 6798c2ecf20Sopenharmony_ci break; 6808c2ecf20Sopenharmony_ci p[0] = TC90522_I2C_THRU_REG; 6818c2ecf20Sopenharmony_ci p[1] = msgs[i].addr << 1; 6828c2ecf20Sopenharmony_ci memcpy(p + 2, msgs[i].buf, msgs[i].len); 6838c2ecf20Sopenharmony_ci new_msgs[j].buf = p; 6848c2ecf20Sopenharmony_ci new_msgs[j].len = msgs[i].len + 2; 6858c2ecf20Sopenharmony_ci p += new_msgs[j].len; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (i < num) { 6898c2ecf20Sopenharmony_ci ret = -ENOMEM; 6908c2ecf20Sopenharmony_ci } else if (!state->cfg.split_tuner_read_i2c || rd_num == 0) { 6918c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c_client->adapter, new_msgs, j); 6928c2ecf20Sopenharmony_ci } else { 6938c2ecf20Sopenharmony_ci /* 6948c2ecf20Sopenharmony_ci * Split transactions at each I2C_M_RD message. 6958c2ecf20Sopenharmony_ci * Some of the parent device require this, 6968c2ecf20Sopenharmony_ci * such as Friio (see. dvb-usb-gl861). 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_ci int from, to; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci ret = 0; 7018c2ecf20Sopenharmony_ci from = 0; 7028c2ecf20Sopenharmony_ci do { 7038c2ecf20Sopenharmony_ci int r; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci to = from + 1; 7068c2ecf20Sopenharmony_ci while (to < j && !(new_msgs[to].flags & I2C_M_RD)) 7078c2ecf20Sopenharmony_ci to++; 7088c2ecf20Sopenharmony_ci r = i2c_transfer(state->i2c_client->adapter, 7098c2ecf20Sopenharmony_ci &new_msgs[from], to - from); 7108c2ecf20Sopenharmony_ci ret = (r <= 0) ? r : ret + r; 7118c2ecf20Sopenharmony_ci from = to; 7128c2ecf20Sopenharmony_ci } while (from < j && ret > 0); 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci if (ret >= 0 && ret < j) 7168c2ecf20Sopenharmony_ci ret = -EIO; 7178c2ecf20Sopenharmony_ci kfree(new_msgs); 7188c2ecf20Sopenharmony_ci return (ret == j) ? num : ret; 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_cistatic u32 tc90522_functionality(struct i2c_adapter *adap) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci return I2C_FUNC_I2C; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic const struct i2c_algorithm tc90522_tuner_i2c_algo = { 7278c2ecf20Sopenharmony_ci .master_xfer = &tc90522_master_xfer, 7288c2ecf20Sopenharmony_ci .functionality = &tc90522_functionality, 7298c2ecf20Sopenharmony_ci}; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci/* 7338c2ecf20Sopenharmony_ci * I2C driver functions 7348c2ecf20Sopenharmony_ci */ 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops tc90522_ops_sat = { 7378c2ecf20Sopenharmony_ci .delsys = { SYS_ISDBS }, 7388c2ecf20Sopenharmony_ci .info = { 7398c2ecf20Sopenharmony_ci .name = "Toshiba TC90522 ISDB-S module", 7408c2ecf20Sopenharmony_ci .frequency_min_hz = 950 * MHz, 7418c2ecf20Sopenharmony_ci .frequency_max_hz = 2150 * MHz, 7428c2ecf20Sopenharmony_ci .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | 7438c2ecf20Sopenharmony_ci FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | 7448c2ecf20Sopenharmony_ci FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, 7458c2ecf20Sopenharmony_ci }, 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci .init = tc90522_init, 7488c2ecf20Sopenharmony_ci .sleep = tc90522_sleep, 7498c2ecf20Sopenharmony_ci .set_frontend = tc90522_set_frontend, 7508c2ecf20Sopenharmony_ci .get_tune_settings = tc90522_get_tune_settings, 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci .get_frontend = tc90522s_get_frontend, 7538c2ecf20Sopenharmony_ci .read_status = tc90522s_read_status, 7548c2ecf20Sopenharmony_ci}; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops tc90522_ops_ter = { 7578c2ecf20Sopenharmony_ci .delsys = { SYS_ISDBT }, 7588c2ecf20Sopenharmony_ci .info = { 7598c2ecf20Sopenharmony_ci .name = "Toshiba TC90522 ISDB-T module", 7608c2ecf20Sopenharmony_ci .frequency_min_hz = 470 * MHz, 7618c2ecf20Sopenharmony_ci .frequency_max_hz = 770 * MHz, 7628c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 142857, 7638c2ecf20Sopenharmony_ci .caps = FE_CAN_INVERSION_AUTO | 7648c2ecf20Sopenharmony_ci FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 7658c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 7668c2ecf20Sopenharmony_ci FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | 7678c2ecf20Sopenharmony_ci FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | 7688c2ecf20Sopenharmony_ci FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | 7698c2ecf20Sopenharmony_ci FE_CAN_HIERARCHY_AUTO, 7708c2ecf20Sopenharmony_ci }, 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci .init = tc90522_init, 7738c2ecf20Sopenharmony_ci .sleep = tc90522_sleep, 7748c2ecf20Sopenharmony_ci .set_frontend = tc90522_set_frontend, 7758c2ecf20Sopenharmony_ci .get_tune_settings = tc90522_get_tune_settings, 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci .get_frontend = tc90522t_get_frontend, 7788c2ecf20Sopenharmony_ci .read_status = tc90522t_read_status, 7798c2ecf20Sopenharmony_ci}; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic int tc90522_probe(struct i2c_client *client, 7838c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci struct tc90522_state *state; 7868c2ecf20Sopenharmony_ci struct tc90522_config *cfg; 7878c2ecf20Sopenharmony_ci const struct dvb_frontend_ops *ops; 7888c2ecf20Sopenharmony_ci struct i2c_adapter *adap; 7898c2ecf20Sopenharmony_ci int ret; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci state = kzalloc(sizeof(*state), GFP_KERNEL); 7928c2ecf20Sopenharmony_ci if (!state) 7938c2ecf20Sopenharmony_ci return -ENOMEM; 7948c2ecf20Sopenharmony_ci state->i2c_client = client; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci cfg = client->dev.platform_data; 7978c2ecf20Sopenharmony_ci memcpy(&state->cfg, cfg, sizeof(state->cfg)); 7988c2ecf20Sopenharmony_ci cfg->fe = state->cfg.fe = &state->fe; 7998c2ecf20Sopenharmony_ci ops = id->driver_data == 0 ? &tc90522_ops_sat : &tc90522_ops_ter; 8008c2ecf20Sopenharmony_ci memcpy(&state->fe.ops, ops, sizeof(*ops)); 8018c2ecf20Sopenharmony_ci state->fe.demodulator_priv = state; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci adap = &state->tuner_i2c; 8048c2ecf20Sopenharmony_ci adap->owner = THIS_MODULE; 8058c2ecf20Sopenharmony_ci adap->algo = &tc90522_tuner_i2c_algo; 8068c2ecf20Sopenharmony_ci adap->dev.parent = &client->dev; 8078c2ecf20Sopenharmony_ci strscpy(adap->name, "tc90522_sub", sizeof(adap->name)); 8088c2ecf20Sopenharmony_ci i2c_set_adapdata(adap, state); 8098c2ecf20Sopenharmony_ci ret = i2c_add_adapter(adap); 8108c2ecf20Sopenharmony_ci if (ret < 0) 8118c2ecf20Sopenharmony_ci goto free_state; 8128c2ecf20Sopenharmony_ci cfg->tuner_i2c = state->cfg.tuner_i2c = adap; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci i2c_set_clientdata(client, &state->cfg); 8158c2ecf20Sopenharmony_ci dev_info(&client->dev, "Toshiba TC90522 attached.\n"); 8168c2ecf20Sopenharmony_ci return 0; 8178c2ecf20Sopenharmony_cifree_state: 8188c2ecf20Sopenharmony_ci kfree(state); 8198c2ecf20Sopenharmony_ci return ret; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic int tc90522_remove(struct i2c_client *client) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci struct tc90522_state *state; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci state = cfg_to_state(i2c_get_clientdata(client)); 8278c2ecf20Sopenharmony_ci i2c_del_adapter(&state->tuner_i2c); 8288c2ecf20Sopenharmony_ci kfree(state); 8298c2ecf20Sopenharmony_ci return 0; 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_cistatic const struct i2c_device_id tc90522_id[] = { 8348c2ecf20Sopenharmony_ci { TC90522_I2C_DEV_SAT, 0 }, 8358c2ecf20Sopenharmony_ci { TC90522_I2C_DEV_TER, 1 }, 8368c2ecf20Sopenharmony_ci {} 8378c2ecf20Sopenharmony_ci}; 8388c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tc90522_id); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic struct i2c_driver tc90522_driver = { 8418c2ecf20Sopenharmony_ci .driver = { 8428c2ecf20Sopenharmony_ci .name = "tc90522", 8438c2ecf20Sopenharmony_ci }, 8448c2ecf20Sopenharmony_ci .probe = tc90522_probe, 8458c2ecf20Sopenharmony_ci .remove = tc90522_remove, 8468c2ecf20Sopenharmony_ci .id_table = tc90522_id, 8478c2ecf20Sopenharmony_ci}; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cimodule_i2c_driver(tc90522_driver); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Toshiba TC90522 frontend"); 8528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Akihiro TSUKADA"); 8538c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 854