18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Fujitu mb86a20s ISDB-T/ISDB-Tsb Module driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010-2013 Mauro Carvalho Chehab 68c2ecf20Sopenharmony_ci * Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <asm/div64.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 138c2ecf20Sopenharmony_ci#include "mb86a20s.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define NUM_LAYERS 3 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cienum mb86a20s_bandwidth { 188c2ecf20Sopenharmony_ci MB86A20S_13SEG = 0, 198c2ecf20Sopenharmony_ci MB86A20S_13SEG_PARTIAL = 1, 208c2ecf20Sopenharmony_ci MB86A20S_1SEG = 2, 218c2ecf20Sopenharmony_ci MB86A20S_3SEG = 3, 228c2ecf20Sopenharmony_ci}; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic u8 mb86a20s_subchannel[] = { 258c2ecf20Sopenharmony_ci 0xb0, 0xc0, 0xd0, 0xe0, 268c2ecf20Sopenharmony_ci 0xf0, 0x00, 0x10, 0x20, 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct mb86a20s_state { 308c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 318c2ecf20Sopenharmony_ci const struct mb86a20s_config *config; 328c2ecf20Sopenharmony_ci u32 last_frequency; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci struct dvb_frontend frontend; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci u32 if_freq; 378c2ecf20Sopenharmony_ci enum mb86a20s_bandwidth bw; 388c2ecf20Sopenharmony_ci bool inversion; 398c2ecf20Sopenharmony_ci u32 subchannel; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci u32 estimated_rate[NUM_LAYERS]; 428c2ecf20Sopenharmony_ci unsigned long get_strength_time; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci bool need_init; 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct regdata { 488c2ecf20Sopenharmony_ci u8 reg; 498c2ecf20Sopenharmony_ci u8 data; 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define BER_SAMPLING_RATE 1 /* Seconds */ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * Initialization sequence: Use whatevere default values that PV SBTVD 568c2ecf20Sopenharmony_ci * does on its initialisation, obtained via USB snoop 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_cistatic struct regdata mb86a20s_init1[] = { 598c2ecf20Sopenharmony_ci { 0x70, 0x0f }, 608c2ecf20Sopenharmony_ci { 0x70, 0xff }, 618c2ecf20Sopenharmony_ci { 0x08, 0x01 }, 628c2ecf20Sopenharmony_ci { 0x50, 0xd1 }, { 0x51, 0x20 }, 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic struct regdata mb86a20s_init2[] = { 668c2ecf20Sopenharmony_ci { 0x50, 0xd1 }, { 0x51, 0x22 }, 678c2ecf20Sopenharmony_ci { 0x39, 0x01 }, 688c2ecf20Sopenharmony_ci { 0x71, 0x00 }, 698c2ecf20Sopenharmony_ci { 0x3b, 0x21 }, 708c2ecf20Sopenharmony_ci { 0x3c, 0x3a }, 718c2ecf20Sopenharmony_ci { 0x01, 0x0d }, 728c2ecf20Sopenharmony_ci { 0x04, 0x08 }, { 0x05, 0x05 }, 738c2ecf20Sopenharmony_ci { 0x04, 0x0e }, { 0x05, 0x00 }, 748c2ecf20Sopenharmony_ci { 0x04, 0x0f }, { 0x05, 0x14 }, 758c2ecf20Sopenharmony_ci { 0x04, 0x0b }, { 0x05, 0x8c }, 768c2ecf20Sopenharmony_ci { 0x04, 0x00 }, { 0x05, 0x00 }, 778c2ecf20Sopenharmony_ci { 0x04, 0x01 }, { 0x05, 0x07 }, 788c2ecf20Sopenharmony_ci { 0x04, 0x02 }, { 0x05, 0x0f }, 798c2ecf20Sopenharmony_ci { 0x04, 0x03 }, { 0x05, 0xa0 }, 808c2ecf20Sopenharmony_ci { 0x04, 0x09 }, { 0x05, 0x00 }, 818c2ecf20Sopenharmony_ci { 0x04, 0x0a }, { 0x05, 0xff }, 828c2ecf20Sopenharmony_ci { 0x04, 0x27 }, { 0x05, 0x64 }, 838c2ecf20Sopenharmony_ci { 0x04, 0x28 }, { 0x05, 0x00 }, 848c2ecf20Sopenharmony_ci { 0x04, 0x1e }, { 0x05, 0xff }, 858c2ecf20Sopenharmony_ci { 0x04, 0x29 }, { 0x05, 0x0a }, 868c2ecf20Sopenharmony_ci { 0x04, 0x32 }, { 0x05, 0x0a }, 878c2ecf20Sopenharmony_ci { 0x04, 0x14 }, { 0x05, 0x02 }, 888c2ecf20Sopenharmony_ci { 0x04, 0x04 }, { 0x05, 0x00 }, 898c2ecf20Sopenharmony_ci { 0x04, 0x05 }, { 0x05, 0x22 }, 908c2ecf20Sopenharmony_ci { 0x04, 0x06 }, { 0x05, 0x0e }, 918c2ecf20Sopenharmony_ci { 0x04, 0x07 }, { 0x05, 0xd8 }, 928c2ecf20Sopenharmony_ci { 0x04, 0x12 }, { 0x05, 0x00 }, 938c2ecf20Sopenharmony_ci { 0x04, 0x13 }, { 0x05, 0xff }, 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* 968c2ecf20Sopenharmony_ci * On this demod, when the bit count reaches the count below, 978c2ecf20Sopenharmony_ci * it collects the bit error count. The bit counters are initialized 988c2ecf20Sopenharmony_ci * to 65535 here. This warrants that all of them will be quickly 998c2ecf20Sopenharmony_ci * calculated when device gets locked. As TMCC is parsed, the values 1008c2ecf20Sopenharmony_ci * will be adjusted later in the driver's code. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci { 0x52, 0x01 }, /* Turn on BER before Viterbi */ 1038c2ecf20Sopenharmony_ci { 0x50, 0xa7 }, { 0x51, 0x00 }, 1048c2ecf20Sopenharmony_ci { 0x50, 0xa8 }, { 0x51, 0xff }, 1058c2ecf20Sopenharmony_ci { 0x50, 0xa9 }, { 0x51, 0xff }, 1068c2ecf20Sopenharmony_ci { 0x50, 0xaa }, { 0x51, 0x00 }, 1078c2ecf20Sopenharmony_ci { 0x50, 0xab }, { 0x51, 0xff }, 1088c2ecf20Sopenharmony_ci { 0x50, 0xac }, { 0x51, 0xff }, 1098c2ecf20Sopenharmony_ci { 0x50, 0xad }, { 0x51, 0x00 }, 1108c2ecf20Sopenharmony_ci { 0x50, 0xae }, { 0x51, 0xff }, 1118c2ecf20Sopenharmony_ci { 0x50, 0xaf }, { 0x51, 0xff }, 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* 1148c2ecf20Sopenharmony_ci * On this demod, post BER counts blocks. When the count reaches the 1158c2ecf20Sopenharmony_ci * value below, it collects the block error count. The block counters 1168c2ecf20Sopenharmony_ci * are initialized to 127 here. This warrants that all of them will be 1178c2ecf20Sopenharmony_ci * quickly calculated when device gets locked. As TMCC is parsed, the 1188c2ecf20Sopenharmony_ci * values will be adjusted later in the driver's code. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci { 0x5e, 0x07 }, /* Turn on BER after Viterbi */ 1218c2ecf20Sopenharmony_ci { 0x50, 0xdc }, { 0x51, 0x00 }, 1228c2ecf20Sopenharmony_ci { 0x50, 0xdd }, { 0x51, 0x7f }, 1238c2ecf20Sopenharmony_ci { 0x50, 0xde }, { 0x51, 0x00 }, 1248c2ecf20Sopenharmony_ci { 0x50, 0xdf }, { 0x51, 0x7f }, 1258c2ecf20Sopenharmony_ci { 0x50, 0xe0 }, { 0x51, 0x00 }, 1268c2ecf20Sopenharmony_ci { 0x50, 0xe1 }, { 0x51, 0x7f }, 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* 1298c2ecf20Sopenharmony_ci * On this demod, when the block count reaches the count below, 1308c2ecf20Sopenharmony_ci * it collects the block error count. The block counters are initialized 1318c2ecf20Sopenharmony_ci * to 127 here. This warrants that all of them will be quickly 1328c2ecf20Sopenharmony_ci * calculated when device gets locked. As TMCC is parsed, the values 1338c2ecf20Sopenharmony_ci * will be adjusted later in the driver's code. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci { 0x50, 0xb0 }, { 0x51, 0x07 }, /* Enable PER */ 1368c2ecf20Sopenharmony_ci { 0x50, 0xb2 }, { 0x51, 0x00 }, 1378c2ecf20Sopenharmony_ci { 0x50, 0xb3 }, { 0x51, 0x7f }, 1388c2ecf20Sopenharmony_ci { 0x50, 0xb4 }, { 0x51, 0x00 }, 1398c2ecf20Sopenharmony_ci { 0x50, 0xb5 }, { 0x51, 0x7f }, 1408c2ecf20Sopenharmony_ci { 0x50, 0xb6 }, { 0x51, 0x00 }, 1418c2ecf20Sopenharmony_ci { 0x50, 0xb7 }, { 0x51, 0x7f }, 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci { 0x50, 0x50 }, { 0x51, 0x02 }, /* MER manual mode */ 1448c2ecf20Sopenharmony_ci { 0x50, 0x51 }, { 0x51, 0x04 }, /* MER symbol 4 */ 1458c2ecf20Sopenharmony_ci { 0x45, 0x04 }, /* CN symbol 4 */ 1468c2ecf20Sopenharmony_ci { 0x48, 0x04 }, /* CN manual mode */ 1478c2ecf20Sopenharmony_ci { 0x50, 0xd5 }, { 0x51, 0x01 }, 1488c2ecf20Sopenharmony_ci { 0x50, 0xd6 }, { 0x51, 0x1f }, 1498c2ecf20Sopenharmony_ci { 0x50, 0xd2 }, { 0x51, 0x03 }, 1508c2ecf20Sopenharmony_ci { 0x50, 0xd7 }, { 0x51, 0x3f }, 1518c2ecf20Sopenharmony_ci { 0x1c, 0x01 }, 1528c2ecf20Sopenharmony_ci { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x03 }, 1538c2ecf20Sopenharmony_ci { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0d }, 1548c2ecf20Sopenharmony_ci { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 }, 1558c2ecf20Sopenharmony_ci { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x01 }, 1568c2ecf20Sopenharmony_ci { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x21 }, 1578c2ecf20Sopenharmony_ci { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x29 }, 1588c2ecf20Sopenharmony_ci { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 }, 1598c2ecf20Sopenharmony_ci { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x31 }, 1608c2ecf20Sopenharmony_ci { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0e }, 1618c2ecf20Sopenharmony_ci { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x4e }, 1628c2ecf20Sopenharmony_ci { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x46 }, 1638c2ecf20Sopenharmony_ci { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f }, 1648c2ecf20Sopenharmony_ci { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x56 }, 1658c2ecf20Sopenharmony_ci { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x35 }, 1668c2ecf20Sopenharmony_ci { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbe }, 1678c2ecf20Sopenharmony_ci { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0x84 }, 1688c2ecf20Sopenharmony_ci { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x03 }, { 0x2b, 0xee }, 1698c2ecf20Sopenharmony_ci { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x98 }, 1708c2ecf20Sopenharmony_ci { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x9f }, 1718c2ecf20Sopenharmony_ci { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xb2 }, 1728c2ecf20Sopenharmony_ci { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0xc2 }, 1738c2ecf20Sopenharmony_ci { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0x4a }, 1748c2ecf20Sopenharmony_ci { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbc }, 1758c2ecf20Sopenharmony_ci { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x04 }, { 0x2b, 0xba }, 1768c2ecf20Sopenharmony_ci { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0x14 }, 1778c2ecf20Sopenharmony_ci { 0x50, 0x1e }, { 0x51, 0x5d }, 1788c2ecf20Sopenharmony_ci { 0x50, 0x22 }, { 0x51, 0x00 }, 1798c2ecf20Sopenharmony_ci { 0x50, 0x23 }, { 0x51, 0xc8 }, 1808c2ecf20Sopenharmony_ci { 0x50, 0x24 }, { 0x51, 0x00 }, 1818c2ecf20Sopenharmony_ci { 0x50, 0x25 }, { 0x51, 0xf0 }, 1828c2ecf20Sopenharmony_ci { 0x50, 0x26 }, { 0x51, 0x00 }, 1838c2ecf20Sopenharmony_ci { 0x50, 0x27 }, { 0x51, 0xc3 }, 1848c2ecf20Sopenharmony_ci { 0x50, 0x39 }, { 0x51, 0x02 }, 1858c2ecf20Sopenharmony_ci { 0x50, 0xd5 }, { 0x51, 0x01 }, 1868c2ecf20Sopenharmony_ci { 0xd0, 0x00 }, 1878c2ecf20Sopenharmony_ci}; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic struct regdata mb86a20s_reset_reception[] = { 1908c2ecf20Sopenharmony_ci { 0x70, 0xf0 }, 1918c2ecf20Sopenharmony_ci { 0x70, 0xff }, 1928c2ecf20Sopenharmony_ci { 0x08, 0x01 }, 1938c2ecf20Sopenharmony_ci { 0x08, 0x00 }, 1948c2ecf20Sopenharmony_ci}; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic struct regdata mb86a20s_per_ber_reset[] = { 1978c2ecf20Sopenharmony_ci { 0x53, 0x00 }, /* pre BER Counter reset */ 1988c2ecf20Sopenharmony_ci { 0x53, 0x07 }, 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci { 0x5f, 0x00 }, /* post BER Counter reset */ 2018c2ecf20Sopenharmony_ci { 0x5f, 0x07 }, 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci { 0x50, 0xb1 }, /* PER Counter reset */ 2048c2ecf20Sopenharmony_ci { 0x51, 0x07 }, 2058c2ecf20Sopenharmony_ci { 0x51, 0x00 }, 2068c2ecf20Sopenharmony_ci}; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/* 2098c2ecf20Sopenharmony_ci * I2C read/write functions and macros 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic int mb86a20s_i2c_writereg(struct mb86a20s_state *state, 2138c2ecf20Sopenharmony_ci u8 i2c_addr, u8 reg, u8 data) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci u8 buf[] = { reg, data }; 2168c2ecf20Sopenharmony_ci struct i2c_msg msg = { 2178c2ecf20Sopenharmony_ci .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2 2188c2ecf20Sopenharmony_ci }; 2198c2ecf20Sopenharmony_ci int rc; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci rc = i2c_transfer(state->i2c, &msg, 1); 2228c2ecf20Sopenharmony_ci if (rc != 1) { 2238c2ecf20Sopenharmony_ci dev_err(&state->i2c->dev, 2248c2ecf20Sopenharmony_ci "%s: writereg error (rc == %i, reg == 0x%02x, data == 0x%02x)\n", 2258c2ecf20Sopenharmony_ci __func__, rc, reg, data); 2268c2ecf20Sopenharmony_ci return rc; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int mb86a20s_i2c_writeregdata(struct mb86a20s_state *state, 2338c2ecf20Sopenharmony_ci u8 i2c_addr, struct regdata *rd, int size) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci int i, rc; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 2388c2ecf20Sopenharmony_ci rc = mb86a20s_i2c_writereg(state, i2c_addr, rd[i].reg, 2398c2ecf20Sopenharmony_ci rd[i].data); 2408c2ecf20Sopenharmony_ci if (rc < 0) 2418c2ecf20Sopenharmony_ci return rc; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int mb86a20s_i2c_readreg(struct mb86a20s_state *state, 2478c2ecf20Sopenharmony_ci u8 i2c_addr, u8 reg) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci u8 val; 2508c2ecf20Sopenharmony_ci int rc; 2518c2ecf20Sopenharmony_ci struct i2c_msg msg[] = { 2528c2ecf20Sopenharmony_ci { .addr = i2c_addr, .flags = 0, .buf = ®, .len = 1 }, 2538c2ecf20Sopenharmony_ci { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 } 2548c2ecf20Sopenharmony_ci }; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci rc = i2c_transfer(state->i2c, msg, 2); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (rc != 2) { 2598c2ecf20Sopenharmony_ci dev_err(&state->i2c->dev, "%s: reg=0x%x (error=%d)\n", 2608c2ecf20Sopenharmony_ci __func__, reg, rc); 2618c2ecf20Sopenharmony_ci return (rc < 0) ? rc : -EIO; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return val; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci#define mb86a20s_readreg(state, reg) \ 2688c2ecf20Sopenharmony_ci mb86a20s_i2c_readreg(state, state->config->demod_address, reg) 2698c2ecf20Sopenharmony_ci#define mb86a20s_writereg(state, reg, val) \ 2708c2ecf20Sopenharmony_ci mb86a20s_i2c_writereg(state, state->config->demod_address, reg, val) 2718c2ecf20Sopenharmony_ci#define mb86a20s_writeregdata(state, regdata) \ 2728c2ecf20Sopenharmony_ci mb86a20s_i2c_writeregdata(state, state->config->demod_address, \ 2738c2ecf20Sopenharmony_ci regdata, ARRAY_SIZE(regdata)) 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci/* 2768c2ecf20Sopenharmony_ci * Ancillary internal routines (likely compiled inlined) 2778c2ecf20Sopenharmony_ci * 2788c2ecf20Sopenharmony_ci * The functions below assume that gateway lock has already obtained 2798c2ecf20Sopenharmony_ci */ 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int mb86a20s_read_status(struct dvb_frontend *fe, enum fe_status *status) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 2848c2ecf20Sopenharmony_ci int val; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci *status = 0; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci val = mb86a20s_readreg(state, 0x0a); 2898c2ecf20Sopenharmony_ci if (val < 0) 2908c2ecf20Sopenharmony_ci return val; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci val &= 0xf; 2938c2ecf20Sopenharmony_ci if (val >= 2) 2948c2ecf20Sopenharmony_ci *status |= FE_HAS_SIGNAL; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (val >= 4) 2978c2ecf20Sopenharmony_ci *status |= FE_HAS_CARRIER; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (val >= 5) 3008c2ecf20Sopenharmony_ci *status |= FE_HAS_VITERBI; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (val >= 7) 3038c2ecf20Sopenharmony_ci *status |= FE_HAS_SYNC; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* 3068c2ecf20Sopenharmony_ci * Actually, on state S8, it starts receiving TS, but the TS 3078c2ecf20Sopenharmony_ci * output is only on normal state after the transition to S9. 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_ci if (val >= 9) 3108c2ecf20Sopenharmony_ci *status |= FE_HAS_LOCK; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s: Status = 0x%02x (state = %d)\n", 3138c2ecf20Sopenharmony_ci __func__, *status, val); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return val; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int mb86a20s_read_signal_strength(struct dvb_frontend *fe) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 3218c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 3228c2ecf20Sopenharmony_ci int rc; 3238c2ecf20Sopenharmony_ci unsigned rf_max, rf_min, rf; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (state->get_strength_time && 3268c2ecf20Sopenharmony_ci (!time_after(jiffies, state->get_strength_time))) 3278c2ecf20Sopenharmony_ci return c->strength.stat[0].uvalue; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* Reset its value if an error happen */ 3308c2ecf20Sopenharmony_ci c->strength.stat[0].uvalue = 0; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Does a binary search to get RF strength */ 3338c2ecf20Sopenharmony_ci rf_max = 0xfff; 3348c2ecf20Sopenharmony_ci rf_min = 0; 3358c2ecf20Sopenharmony_ci do { 3368c2ecf20Sopenharmony_ci rf = (rf_max + rf_min) / 2; 3378c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x04, 0x1f); 3388c2ecf20Sopenharmony_ci if (rc < 0) 3398c2ecf20Sopenharmony_ci return rc; 3408c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x05, rf >> 8); 3418c2ecf20Sopenharmony_ci if (rc < 0) 3428c2ecf20Sopenharmony_ci return rc; 3438c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x04, 0x20); 3448c2ecf20Sopenharmony_ci if (rc < 0) 3458c2ecf20Sopenharmony_ci return rc; 3468c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x05, rf); 3478c2ecf20Sopenharmony_ci if (rc < 0) 3488c2ecf20Sopenharmony_ci return rc; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x02); 3518c2ecf20Sopenharmony_ci if (rc < 0) 3528c2ecf20Sopenharmony_ci return rc; 3538c2ecf20Sopenharmony_ci if (rc & 0x08) 3548c2ecf20Sopenharmony_ci rf_min = (rf_max + rf_min) / 2; 3558c2ecf20Sopenharmony_ci else 3568c2ecf20Sopenharmony_ci rf_max = (rf_max + rf_min) / 2; 3578c2ecf20Sopenharmony_ci if (rf_max - rf_min < 4) { 3588c2ecf20Sopenharmony_ci rf = (rf_max + rf_min) / 2; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Rescale it from 2^12 (4096) to 2^16 */ 3618c2ecf20Sopenharmony_ci rf = rf << (16 - 12); 3628c2ecf20Sopenharmony_ci if (rf) 3638c2ecf20Sopenharmony_ci rf |= (1 << 12) - 1; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 3668c2ecf20Sopenharmony_ci "%s: signal strength = %d (%d < RF=%d < %d)\n", 3678c2ecf20Sopenharmony_ci __func__, rf, rf_min, rf >> 4, rf_max); 3688c2ecf20Sopenharmony_ci c->strength.stat[0].uvalue = rf; 3698c2ecf20Sopenharmony_ci state->get_strength_time = jiffies + 3708c2ecf20Sopenharmony_ci msecs_to_jiffies(1000); 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci } while (1); 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic int mb86a20s_get_modulation(struct mb86a20s_state *state, 3778c2ecf20Sopenharmony_ci unsigned layer) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci int rc; 3808c2ecf20Sopenharmony_ci static unsigned char reg[] = { 3818c2ecf20Sopenharmony_ci [0] = 0x86, /* Layer A */ 3828c2ecf20Sopenharmony_ci [1] = 0x8a, /* Layer B */ 3838c2ecf20Sopenharmony_ci [2] = 0x8e, /* Layer C */ 3848c2ecf20Sopenharmony_ci }; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (layer >= ARRAY_SIZE(reg)) 3878c2ecf20Sopenharmony_ci return -EINVAL; 3888c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x6d, reg[layer]); 3898c2ecf20Sopenharmony_ci if (rc < 0) 3908c2ecf20Sopenharmony_ci return rc; 3918c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x6e); 3928c2ecf20Sopenharmony_ci if (rc < 0) 3938c2ecf20Sopenharmony_ci return rc; 3948c2ecf20Sopenharmony_ci switch ((rc >> 4) & 0x07) { 3958c2ecf20Sopenharmony_ci case 0: 3968c2ecf20Sopenharmony_ci return DQPSK; 3978c2ecf20Sopenharmony_ci case 1: 3988c2ecf20Sopenharmony_ci return QPSK; 3998c2ecf20Sopenharmony_ci case 2: 4008c2ecf20Sopenharmony_ci return QAM_16; 4018c2ecf20Sopenharmony_ci case 3: 4028c2ecf20Sopenharmony_ci return QAM_64; 4038c2ecf20Sopenharmony_ci default: 4048c2ecf20Sopenharmony_ci return QAM_AUTO; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic int mb86a20s_get_fec(struct mb86a20s_state *state, 4098c2ecf20Sopenharmony_ci unsigned layer) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci int rc; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci static unsigned char reg[] = { 4148c2ecf20Sopenharmony_ci [0] = 0x87, /* Layer A */ 4158c2ecf20Sopenharmony_ci [1] = 0x8b, /* Layer B */ 4168c2ecf20Sopenharmony_ci [2] = 0x8f, /* Layer C */ 4178c2ecf20Sopenharmony_ci }; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (layer >= ARRAY_SIZE(reg)) 4208c2ecf20Sopenharmony_ci return -EINVAL; 4218c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x6d, reg[layer]); 4228c2ecf20Sopenharmony_ci if (rc < 0) 4238c2ecf20Sopenharmony_ci return rc; 4248c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x6e); 4258c2ecf20Sopenharmony_ci if (rc < 0) 4268c2ecf20Sopenharmony_ci return rc; 4278c2ecf20Sopenharmony_ci switch ((rc >> 4) & 0x07) { 4288c2ecf20Sopenharmony_ci case 0: 4298c2ecf20Sopenharmony_ci return FEC_1_2; 4308c2ecf20Sopenharmony_ci case 1: 4318c2ecf20Sopenharmony_ci return FEC_2_3; 4328c2ecf20Sopenharmony_ci case 2: 4338c2ecf20Sopenharmony_ci return FEC_3_4; 4348c2ecf20Sopenharmony_ci case 3: 4358c2ecf20Sopenharmony_ci return FEC_5_6; 4368c2ecf20Sopenharmony_ci case 4: 4378c2ecf20Sopenharmony_ci return FEC_7_8; 4388c2ecf20Sopenharmony_ci default: 4398c2ecf20Sopenharmony_ci return FEC_AUTO; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic int mb86a20s_get_interleaving(struct mb86a20s_state *state, 4448c2ecf20Sopenharmony_ci unsigned layer) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci int rc; 4478c2ecf20Sopenharmony_ci int interleaving[] = { 4488c2ecf20Sopenharmony_ci 0, 1, 2, 4, 8 4498c2ecf20Sopenharmony_ci }; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci static unsigned char reg[] = { 4528c2ecf20Sopenharmony_ci [0] = 0x88, /* Layer A */ 4538c2ecf20Sopenharmony_ci [1] = 0x8c, /* Layer B */ 4548c2ecf20Sopenharmony_ci [2] = 0x90, /* Layer C */ 4558c2ecf20Sopenharmony_ci }; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (layer >= ARRAY_SIZE(reg)) 4588c2ecf20Sopenharmony_ci return -EINVAL; 4598c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x6d, reg[layer]); 4608c2ecf20Sopenharmony_ci if (rc < 0) 4618c2ecf20Sopenharmony_ci return rc; 4628c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x6e); 4638c2ecf20Sopenharmony_ci if (rc < 0) 4648c2ecf20Sopenharmony_ci return rc; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci return interleaving[(rc >> 4) & 0x07]; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic int mb86a20s_get_segment_count(struct mb86a20s_state *state, 4708c2ecf20Sopenharmony_ci unsigned layer) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci int rc, count; 4738c2ecf20Sopenharmony_ci static unsigned char reg[] = { 4748c2ecf20Sopenharmony_ci [0] = 0x89, /* Layer A */ 4758c2ecf20Sopenharmony_ci [1] = 0x8d, /* Layer B */ 4768c2ecf20Sopenharmony_ci [2] = 0x91, /* Layer C */ 4778c2ecf20Sopenharmony_ci }; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (layer >= ARRAY_SIZE(reg)) 4828c2ecf20Sopenharmony_ci return -EINVAL; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x6d, reg[layer]); 4858c2ecf20Sopenharmony_ci if (rc < 0) 4868c2ecf20Sopenharmony_ci return rc; 4878c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x6e); 4888c2ecf20Sopenharmony_ci if (rc < 0) 4898c2ecf20Sopenharmony_ci return rc; 4908c2ecf20Sopenharmony_ci count = (rc >> 4) & 0x0f; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s: segments: %d.\n", __func__, count); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return count; 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic void mb86a20s_reset_frontend_cache(struct dvb_frontend *fe) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 5008c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* Fixed parameters */ 5058c2ecf20Sopenharmony_ci c->delivery_system = SYS_ISDBT; 5068c2ecf20Sopenharmony_ci c->bandwidth_hz = 6000000; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* Initialize values that will be later autodetected */ 5098c2ecf20Sopenharmony_ci c->isdbt_layer_enabled = 0; 5108c2ecf20Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_AUTO; 5118c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_AUTO; 5128c2ecf20Sopenharmony_ci c->isdbt_sb_mode = 0; 5138c2ecf20Sopenharmony_ci c->isdbt_sb_segment_count = 0; 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci/* 5178c2ecf20Sopenharmony_ci * Estimates the bit rate using the per-segment bit rate given by 5188c2ecf20Sopenharmony_ci * ABNT/NBR 15601 spec (table 4). 5198c2ecf20Sopenharmony_ci */ 5208c2ecf20Sopenharmony_cistatic const u32 isdbt_rate[3][5][4] = { 5218c2ecf20Sopenharmony_ci { /* DQPSK/QPSK */ 5228c2ecf20Sopenharmony_ci { 280850, 312060, 330420, 340430 }, /* 1/2 */ 5238c2ecf20Sopenharmony_ci { 374470, 416080, 440560, 453910 }, /* 2/3 */ 5248c2ecf20Sopenharmony_ci { 421280, 468090, 495630, 510650 }, /* 3/4 */ 5258c2ecf20Sopenharmony_ci { 468090, 520100, 550700, 567390 }, /* 5/6 */ 5268c2ecf20Sopenharmony_ci { 491500, 546110, 578230, 595760 }, /* 7/8 */ 5278c2ecf20Sopenharmony_ci }, { /* QAM16 */ 5288c2ecf20Sopenharmony_ci { 561710, 624130, 660840, 680870 }, /* 1/2 */ 5298c2ecf20Sopenharmony_ci { 748950, 832170, 881120, 907820 }, /* 2/3 */ 5308c2ecf20Sopenharmony_ci { 842570, 936190, 991260, 1021300 }, /* 3/4 */ 5318c2ecf20Sopenharmony_ci { 936190, 1040210, 1101400, 1134780 }, /* 5/6 */ 5328c2ecf20Sopenharmony_ci { 983000, 1092220, 1156470, 1191520 }, /* 7/8 */ 5338c2ecf20Sopenharmony_ci }, { /* QAM64 */ 5348c2ecf20Sopenharmony_ci { 842570, 936190, 991260, 1021300 }, /* 1/2 */ 5358c2ecf20Sopenharmony_ci { 1123430, 1248260, 1321680, 1361740 }, /* 2/3 */ 5368c2ecf20Sopenharmony_ci { 1263860, 1404290, 1486900, 1531950 }, /* 3/4 */ 5378c2ecf20Sopenharmony_ci { 1404290, 1560320, 1652110, 1702170 }, /* 5/6 */ 5388c2ecf20Sopenharmony_ci { 1474500, 1638340, 1734710, 1787280 }, /* 7/8 */ 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci}; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic u32 isdbt_layer_min_bitrate(struct dtv_frontend_properties *c, 5438c2ecf20Sopenharmony_ci u32 layer) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci int mod, fec, guard; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* 5488c2ecf20Sopenharmony_ci * If modulation/fec/guard is not detected, the default is 5498c2ecf20Sopenharmony_ci * to consider the lowest bit rate, to avoid taking too long time 5508c2ecf20Sopenharmony_ci * to get BER. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_ci switch (c->layer[layer].modulation) { 5538c2ecf20Sopenharmony_ci case DQPSK: 5548c2ecf20Sopenharmony_ci case QPSK: 5558c2ecf20Sopenharmony_ci default: 5568c2ecf20Sopenharmony_ci mod = 0; 5578c2ecf20Sopenharmony_ci break; 5588c2ecf20Sopenharmony_ci case QAM_16: 5598c2ecf20Sopenharmony_ci mod = 1; 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci case QAM_64: 5628c2ecf20Sopenharmony_ci mod = 2; 5638c2ecf20Sopenharmony_ci break; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci switch (c->layer[layer].fec) { 5678c2ecf20Sopenharmony_ci default: 5688c2ecf20Sopenharmony_ci case FEC_1_2: 5698c2ecf20Sopenharmony_ci case FEC_AUTO: 5708c2ecf20Sopenharmony_ci fec = 0; 5718c2ecf20Sopenharmony_ci break; 5728c2ecf20Sopenharmony_ci case FEC_2_3: 5738c2ecf20Sopenharmony_ci fec = 1; 5748c2ecf20Sopenharmony_ci break; 5758c2ecf20Sopenharmony_ci case FEC_3_4: 5768c2ecf20Sopenharmony_ci fec = 2; 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci case FEC_5_6: 5798c2ecf20Sopenharmony_ci fec = 3; 5808c2ecf20Sopenharmony_ci break; 5818c2ecf20Sopenharmony_ci case FEC_7_8: 5828c2ecf20Sopenharmony_ci fec = 4; 5838c2ecf20Sopenharmony_ci break; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci switch (c->guard_interval) { 5878c2ecf20Sopenharmony_ci default: 5888c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_4: 5898c2ecf20Sopenharmony_ci guard = 0; 5908c2ecf20Sopenharmony_ci break; 5918c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_8: 5928c2ecf20Sopenharmony_ci guard = 1; 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_16: 5958c2ecf20Sopenharmony_ci guard = 2; 5968c2ecf20Sopenharmony_ci break; 5978c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_32: 5988c2ecf20Sopenharmony_ci guard = 3; 5998c2ecf20Sopenharmony_ci break; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci return isdbt_rate[mod][fec][guard] * c->layer[layer].segment_count; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic int mb86a20s_get_frontend(struct dvb_frontend *fe) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 6088c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 6098c2ecf20Sopenharmony_ci int layer, rc, rate, counter; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci /* Reset frontend cache to default values */ 6148c2ecf20Sopenharmony_ci mb86a20s_reset_frontend_cache(fe); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* Check for partial reception */ 6178c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x6d, 0x85); 6188c2ecf20Sopenharmony_ci if (rc < 0) 6198c2ecf20Sopenharmony_ci return rc; 6208c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x6e); 6218c2ecf20Sopenharmony_ci if (rc < 0) 6228c2ecf20Sopenharmony_ci return rc; 6238c2ecf20Sopenharmony_ci c->isdbt_partial_reception = (rc & 0x10) ? 1 : 0; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* Get per-layer data */ 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci for (layer = 0; layer < NUM_LAYERS; layer++) { 6288c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s: getting data for layer %c.\n", 6298c2ecf20Sopenharmony_ci __func__, 'A' + layer); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci rc = mb86a20s_get_segment_count(state, layer); 6328c2ecf20Sopenharmony_ci if (rc < 0) 6338c2ecf20Sopenharmony_ci goto noperlayer_error; 6348c2ecf20Sopenharmony_ci if (rc >= 0 && rc < 14) { 6358c2ecf20Sopenharmony_ci c->layer[layer].segment_count = rc; 6368c2ecf20Sopenharmony_ci } else { 6378c2ecf20Sopenharmony_ci c->layer[layer].segment_count = 0; 6388c2ecf20Sopenharmony_ci state->estimated_rate[layer] = 0; 6398c2ecf20Sopenharmony_ci continue; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci c->isdbt_layer_enabled |= 1 << layer; 6428c2ecf20Sopenharmony_ci rc = mb86a20s_get_modulation(state, layer); 6438c2ecf20Sopenharmony_ci if (rc < 0) 6448c2ecf20Sopenharmony_ci goto noperlayer_error; 6458c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s: modulation %d.\n", 6468c2ecf20Sopenharmony_ci __func__, rc); 6478c2ecf20Sopenharmony_ci c->layer[layer].modulation = rc; 6488c2ecf20Sopenharmony_ci rc = mb86a20s_get_fec(state, layer); 6498c2ecf20Sopenharmony_ci if (rc < 0) 6508c2ecf20Sopenharmony_ci goto noperlayer_error; 6518c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s: FEC %d.\n", 6528c2ecf20Sopenharmony_ci __func__, rc); 6538c2ecf20Sopenharmony_ci c->layer[layer].fec = rc; 6548c2ecf20Sopenharmony_ci rc = mb86a20s_get_interleaving(state, layer); 6558c2ecf20Sopenharmony_ci if (rc < 0) 6568c2ecf20Sopenharmony_ci goto noperlayer_error; 6578c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s: interleaving %d.\n", 6588c2ecf20Sopenharmony_ci __func__, rc); 6598c2ecf20Sopenharmony_ci c->layer[layer].interleaving = rc; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci rate = isdbt_layer_min_bitrate(c, layer); 6628c2ecf20Sopenharmony_ci counter = rate * BER_SAMPLING_RATE; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* Avoids sampling too quickly or to overflow the register */ 6658c2ecf20Sopenharmony_ci if (counter < 256) 6668c2ecf20Sopenharmony_ci counter = 256; 6678c2ecf20Sopenharmony_ci else if (counter > (1 << 24) - 1) 6688c2ecf20Sopenharmony_ci counter = (1 << 24) - 1; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 6718c2ecf20Sopenharmony_ci "%s: layer %c bitrate: %d kbps; counter = %d (0x%06x)\n", 6728c2ecf20Sopenharmony_ci __func__, 'A' + layer, rate / 1000, counter, counter); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci state->estimated_rate[layer] = counter; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x6d, 0x84); 6788c2ecf20Sopenharmony_ci if (rc < 0) 6798c2ecf20Sopenharmony_ci return rc; 6808c2ecf20Sopenharmony_ci if ((rc & 0x60) == 0x20) { 6818c2ecf20Sopenharmony_ci c->isdbt_sb_mode = 1; 6828c2ecf20Sopenharmony_ci /* At least, one segment should exist */ 6838c2ecf20Sopenharmony_ci if (!c->isdbt_sb_segment_count) 6848c2ecf20Sopenharmony_ci c->isdbt_sb_segment_count = 1; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* Get transmission mode and guard interval */ 6888c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x07); 6898c2ecf20Sopenharmony_ci if (rc < 0) 6908c2ecf20Sopenharmony_ci return rc; 6918c2ecf20Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_AUTO; 6928c2ecf20Sopenharmony_ci if ((rc & 0x60) == 0x20) { 6938c2ecf20Sopenharmony_ci /* Only modes 2 and 3 are supported */ 6948c2ecf20Sopenharmony_ci switch ((rc >> 2) & 0x03) { 6958c2ecf20Sopenharmony_ci case 1: 6968c2ecf20Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_4K; 6978c2ecf20Sopenharmony_ci break; 6988c2ecf20Sopenharmony_ci case 2: 6998c2ecf20Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_8K; 7008c2ecf20Sopenharmony_ci break; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_AUTO; 7048c2ecf20Sopenharmony_ci if (!(rc & 0x10)) { 7058c2ecf20Sopenharmony_ci /* Guard interval 1/32 is not supported */ 7068c2ecf20Sopenharmony_ci switch (rc & 0x3) { 7078c2ecf20Sopenharmony_ci case 0: 7088c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_4; 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci case 1: 7118c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_8; 7128c2ecf20Sopenharmony_ci break; 7138c2ecf20Sopenharmony_ci case 2: 7148c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_16; 7158c2ecf20Sopenharmony_ci break; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci return 0; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cinoperlayer_error: 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* per-layer info is incomplete; discard all per-layer */ 7238c2ecf20Sopenharmony_ci c->isdbt_layer_enabled = 0; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return rc; 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cistatic int mb86a20s_reset_counters(struct dvb_frontend *fe) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 7318c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 7328c2ecf20Sopenharmony_ci int rc, val; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* Reset the counters, if the channel changed */ 7378c2ecf20Sopenharmony_ci if (state->last_frequency != c->frequency) { 7388c2ecf20Sopenharmony_ci memset(&c->cnr, 0, sizeof(c->cnr)); 7398c2ecf20Sopenharmony_ci memset(&c->pre_bit_error, 0, sizeof(c->pre_bit_error)); 7408c2ecf20Sopenharmony_ci memset(&c->pre_bit_count, 0, sizeof(c->pre_bit_count)); 7418c2ecf20Sopenharmony_ci memset(&c->post_bit_error, 0, sizeof(c->post_bit_error)); 7428c2ecf20Sopenharmony_ci memset(&c->post_bit_count, 0, sizeof(c->post_bit_count)); 7438c2ecf20Sopenharmony_ci memset(&c->block_error, 0, sizeof(c->block_error)); 7448c2ecf20Sopenharmony_ci memset(&c->block_count, 0, sizeof(c->block_count)); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci state->last_frequency = c->frequency; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* Clear status for most stats */ 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* BER/PER counter reset */ 7528c2ecf20Sopenharmony_ci rc = mb86a20s_writeregdata(state, mb86a20s_per_ber_reset); 7538c2ecf20Sopenharmony_ci if (rc < 0) 7548c2ecf20Sopenharmony_ci goto err; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* CNR counter reset */ 7578c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x45); 7588c2ecf20Sopenharmony_ci if (rc < 0) 7598c2ecf20Sopenharmony_ci goto err; 7608c2ecf20Sopenharmony_ci val = rc; 7618c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x45, val | 0x10); 7628c2ecf20Sopenharmony_ci if (rc < 0) 7638c2ecf20Sopenharmony_ci goto err; 7648c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x45, val & 0x6f); 7658c2ecf20Sopenharmony_ci if (rc < 0) 7668c2ecf20Sopenharmony_ci goto err; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* MER counter reset */ 7698c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0x50); 7708c2ecf20Sopenharmony_ci if (rc < 0) 7718c2ecf20Sopenharmony_ci goto err; 7728c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 7738c2ecf20Sopenharmony_ci if (rc < 0) 7748c2ecf20Sopenharmony_ci goto err; 7758c2ecf20Sopenharmony_ci val = rc; 7768c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, val | 0x01); 7778c2ecf20Sopenharmony_ci if (rc < 0) 7788c2ecf20Sopenharmony_ci goto err; 7798c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, val & 0x06); 7808c2ecf20Sopenharmony_ci if (rc < 0) 7818c2ecf20Sopenharmony_ci goto err; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci goto ok; 7848c2ecf20Sopenharmony_cierr: 7858c2ecf20Sopenharmony_ci dev_err(&state->i2c->dev, 7868c2ecf20Sopenharmony_ci "%s: Can't reset FE statistics (error %d).\n", 7878c2ecf20Sopenharmony_ci __func__, rc); 7888c2ecf20Sopenharmony_ciok: 7898c2ecf20Sopenharmony_ci return rc; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic int mb86a20s_get_pre_ber(struct dvb_frontend *fe, 7938c2ecf20Sopenharmony_ci unsigned layer, 7948c2ecf20Sopenharmony_ci u32 *error, u32 *count) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 7978c2ecf20Sopenharmony_ci int rc, val; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (layer >= NUM_LAYERS) 8028c2ecf20Sopenharmony_ci return -EINVAL; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* Check if the BER measures are already available */ 8058c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x54); 8068c2ecf20Sopenharmony_ci if (rc < 0) 8078c2ecf20Sopenharmony_ci return rc; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* Check if data is available for that layer */ 8108c2ecf20Sopenharmony_ci if (!(rc & (1 << layer))) { 8118c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 8128c2ecf20Sopenharmony_ci "%s: preBER for layer %c is not available yet.\n", 8138c2ecf20Sopenharmony_ci __func__, 'A' + layer); 8148c2ecf20Sopenharmony_ci return -EBUSY; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* Read Bit Error Count */ 8188c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x55 + layer * 3); 8198c2ecf20Sopenharmony_ci if (rc < 0) 8208c2ecf20Sopenharmony_ci return rc; 8218c2ecf20Sopenharmony_ci *error = rc << 16; 8228c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x56 + layer * 3); 8238c2ecf20Sopenharmony_ci if (rc < 0) 8248c2ecf20Sopenharmony_ci return rc; 8258c2ecf20Sopenharmony_ci *error |= rc << 8; 8268c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x57 + layer * 3); 8278c2ecf20Sopenharmony_ci if (rc < 0) 8288c2ecf20Sopenharmony_ci return rc; 8298c2ecf20Sopenharmony_ci *error |= rc; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 8328c2ecf20Sopenharmony_ci "%s: bit error before Viterbi for layer %c: %d.\n", 8338c2ecf20Sopenharmony_ci __func__, 'A' + layer, *error); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci /* Read Bit Count */ 8368c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xa7 + layer * 3); 8378c2ecf20Sopenharmony_ci if (rc < 0) 8388c2ecf20Sopenharmony_ci return rc; 8398c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 8408c2ecf20Sopenharmony_ci if (rc < 0) 8418c2ecf20Sopenharmony_ci return rc; 8428c2ecf20Sopenharmony_ci *count = rc << 16; 8438c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xa8 + layer * 3); 8448c2ecf20Sopenharmony_ci if (rc < 0) 8458c2ecf20Sopenharmony_ci return rc; 8468c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 8478c2ecf20Sopenharmony_ci if (rc < 0) 8488c2ecf20Sopenharmony_ci return rc; 8498c2ecf20Sopenharmony_ci *count |= rc << 8; 8508c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xa9 + layer * 3); 8518c2ecf20Sopenharmony_ci if (rc < 0) 8528c2ecf20Sopenharmony_ci return rc; 8538c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 8548c2ecf20Sopenharmony_ci if (rc < 0) 8558c2ecf20Sopenharmony_ci return rc; 8568c2ecf20Sopenharmony_ci *count |= rc; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 8598c2ecf20Sopenharmony_ci "%s: bit count before Viterbi for layer %c: %d.\n", 8608c2ecf20Sopenharmony_ci __func__, 'A' + layer, *count); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* 8648c2ecf20Sopenharmony_ci * As we get TMCC data from the frontend, we can better estimate the 8658c2ecf20Sopenharmony_ci * BER bit counters, in order to do the BER measure during a longer 8668c2ecf20Sopenharmony_ci * time. Use those data, if available, to update the bit count 8678c2ecf20Sopenharmony_ci * measure. 8688c2ecf20Sopenharmony_ci */ 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci if (state->estimated_rate[layer] 8718c2ecf20Sopenharmony_ci && state->estimated_rate[layer] != *count) { 8728c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 8738c2ecf20Sopenharmony_ci "%s: updating layer %c preBER counter to %d.\n", 8748c2ecf20Sopenharmony_ci __func__, 'A' + layer, state->estimated_rate[layer]); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci /* Turn off BER before Viterbi */ 8778c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x52, 0x00); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci /* Update counter for this layer */ 8808c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xa7 + layer * 3); 8818c2ecf20Sopenharmony_ci if (rc < 0) 8828c2ecf20Sopenharmony_ci return rc; 8838c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, 8848c2ecf20Sopenharmony_ci state->estimated_rate[layer] >> 16); 8858c2ecf20Sopenharmony_ci if (rc < 0) 8868c2ecf20Sopenharmony_ci return rc; 8878c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xa8 + layer * 3); 8888c2ecf20Sopenharmony_ci if (rc < 0) 8898c2ecf20Sopenharmony_ci return rc; 8908c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, 8918c2ecf20Sopenharmony_ci state->estimated_rate[layer] >> 8); 8928c2ecf20Sopenharmony_ci if (rc < 0) 8938c2ecf20Sopenharmony_ci return rc; 8948c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xa9 + layer * 3); 8958c2ecf20Sopenharmony_ci if (rc < 0) 8968c2ecf20Sopenharmony_ci return rc; 8978c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, 8988c2ecf20Sopenharmony_ci state->estimated_rate[layer]); 8998c2ecf20Sopenharmony_ci if (rc < 0) 9008c2ecf20Sopenharmony_ci return rc; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci /* Turn on BER before Viterbi */ 9038c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x52, 0x01); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* Reset all preBER counters */ 9068c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x53, 0x00); 9078c2ecf20Sopenharmony_ci if (rc < 0) 9088c2ecf20Sopenharmony_ci return rc; 9098c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x53, 0x07); 9108c2ecf20Sopenharmony_ci } else { 9118c2ecf20Sopenharmony_ci /* Reset counter to collect new data */ 9128c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x53); 9138c2ecf20Sopenharmony_ci if (rc < 0) 9148c2ecf20Sopenharmony_ci return rc; 9158c2ecf20Sopenharmony_ci val = rc; 9168c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x53, val & ~(1 << layer)); 9178c2ecf20Sopenharmony_ci if (rc < 0) 9188c2ecf20Sopenharmony_ci return rc; 9198c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x53, val | (1 << layer)); 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci return rc; 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cistatic int mb86a20s_get_post_ber(struct dvb_frontend *fe, 9268c2ecf20Sopenharmony_ci unsigned layer, 9278c2ecf20Sopenharmony_ci u32 *error, u32 *count) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 9308c2ecf20Sopenharmony_ci u32 counter, collect_rate; 9318c2ecf20Sopenharmony_ci int rc, val; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (layer >= NUM_LAYERS) 9368c2ecf20Sopenharmony_ci return -EINVAL; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci /* Check if the BER measures are already available */ 9398c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x60); 9408c2ecf20Sopenharmony_ci if (rc < 0) 9418c2ecf20Sopenharmony_ci return rc; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* Check if data is available for that layer */ 9448c2ecf20Sopenharmony_ci if (!(rc & (1 << layer))) { 9458c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 9468c2ecf20Sopenharmony_ci "%s: post BER for layer %c is not available yet.\n", 9478c2ecf20Sopenharmony_ci __func__, 'A' + layer); 9488c2ecf20Sopenharmony_ci return -EBUSY; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci /* Read Bit Error Count */ 9528c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x64 + layer * 3); 9538c2ecf20Sopenharmony_ci if (rc < 0) 9548c2ecf20Sopenharmony_ci return rc; 9558c2ecf20Sopenharmony_ci *error = rc << 16; 9568c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x65 + layer * 3); 9578c2ecf20Sopenharmony_ci if (rc < 0) 9588c2ecf20Sopenharmony_ci return rc; 9598c2ecf20Sopenharmony_ci *error |= rc << 8; 9608c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x66 + layer * 3); 9618c2ecf20Sopenharmony_ci if (rc < 0) 9628c2ecf20Sopenharmony_ci return rc; 9638c2ecf20Sopenharmony_ci *error |= rc; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 9668c2ecf20Sopenharmony_ci "%s: post bit error for layer %c: %d.\n", 9678c2ecf20Sopenharmony_ci __func__, 'A' + layer, *error); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci /* Read Bit Count */ 9708c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xdc + layer * 2); 9718c2ecf20Sopenharmony_ci if (rc < 0) 9728c2ecf20Sopenharmony_ci return rc; 9738c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 9748c2ecf20Sopenharmony_ci if (rc < 0) 9758c2ecf20Sopenharmony_ci return rc; 9768c2ecf20Sopenharmony_ci counter = rc << 8; 9778c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xdd + layer * 2); 9788c2ecf20Sopenharmony_ci if (rc < 0) 9798c2ecf20Sopenharmony_ci return rc; 9808c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 9818c2ecf20Sopenharmony_ci if (rc < 0) 9828c2ecf20Sopenharmony_ci return rc; 9838c2ecf20Sopenharmony_ci counter |= rc; 9848c2ecf20Sopenharmony_ci *count = counter * 204 * 8; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 9878c2ecf20Sopenharmony_ci "%s: post bit count for layer %c: %d.\n", 9888c2ecf20Sopenharmony_ci __func__, 'A' + layer, *count); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* 9918c2ecf20Sopenharmony_ci * As we get TMCC data from the frontend, we can better estimate the 9928c2ecf20Sopenharmony_ci * BER bit counters, in order to do the BER measure during a longer 9938c2ecf20Sopenharmony_ci * time. Use those data, if available, to update the bit count 9948c2ecf20Sopenharmony_ci * measure. 9958c2ecf20Sopenharmony_ci */ 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci if (!state->estimated_rate[layer]) 9988c2ecf20Sopenharmony_ci goto reset_measurement; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci collect_rate = state->estimated_rate[layer] / 204 / 8; 10018c2ecf20Sopenharmony_ci if (collect_rate < 32) 10028c2ecf20Sopenharmony_ci collect_rate = 32; 10038c2ecf20Sopenharmony_ci if (collect_rate > 65535) 10048c2ecf20Sopenharmony_ci collect_rate = 65535; 10058c2ecf20Sopenharmony_ci if (collect_rate != counter) { 10068c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 10078c2ecf20Sopenharmony_ci "%s: updating postBER counter on layer %c to %d.\n", 10088c2ecf20Sopenharmony_ci __func__, 'A' + layer, collect_rate); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci /* Turn off BER after Viterbi */ 10118c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x5e, 0x00); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci /* Update counter for this layer */ 10148c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xdc + layer * 2); 10158c2ecf20Sopenharmony_ci if (rc < 0) 10168c2ecf20Sopenharmony_ci return rc; 10178c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, collect_rate >> 8); 10188c2ecf20Sopenharmony_ci if (rc < 0) 10198c2ecf20Sopenharmony_ci return rc; 10208c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xdd + layer * 2); 10218c2ecf20Sopenharmony_ci if (rc < 0) 10228c2ecf20Sopenharmony_ci return rc; 10238c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, collect_rate & 0xff); 10248c2ecf20Sopenharmony_ci if (rc < 0) 10258c2ecf20Sopenharmony_ci return rc; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* Turn on BER after Viterbi */ 10288c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x5e, 0x07); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* Reset all preBER counters */ 10318c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x5f, 0x00); 10328c2ecf20Sopenharmony_ci if (rc < 0) 10338c2ecf20Sopenharmony_ci return rc; 10348c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x5f, 0x07); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci return rc; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cireset_measurement: 10408c2ecf20Sopenharmony_ci /* Reset counter to collect new data */ 10418c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x5f); 10428c2ecf20Sopenharmony_ci if (rc < 0) 10438c2ecf20Sopenharmony_ci return rc; 10448c2ecf20Sopenharmony_ci val = rc; 10458c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x5f, val & ~(1 << layer)); 10468c2ecf20Sopenharmony_ci if (rc < 0) 10478c2ecf20Sopenharmony_ci return rc; 10488c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x5f, val | (1 << layer)); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci return rc; 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cistatic int mb86a20s_get_blk_error(struct dvb_frontend *fe, 10548c2ecf20Sopenharmony_ci unsigned layer, 10558c2ecf20Sopenharmony_ci u32 *error, u32 *count) 10568c2ecf20Sopenharmony_ci{ 10578c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 10588c2ecf20Sopenharmony_ci int rc, val; 10598c2ecf20Sopenharmony_ci u32 collect_rate; 10608c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci if (layer >= NUM_LAYERS) 10638c2ecf20Sopenharmony_ci return -EINVAL; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci /* Check if the PER measures are already available */ 10668c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xb8); 10678c2ecf20Sopenharmony_ci if (rc < 0) 10688c2ecf20Sopenharmony_ci return rc; 10698c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 10708c2ecf20Sopenharmony_ci if (rc < 0) 10718c2ecf20Sopenharmony_ci return rc; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* Check if data is available for that layer */ 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci if (!(rc & (1 << layer))) { 10768c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 10778c2ecf20Sopenharmony_ci "%s: block counts for layer %c aren't available yet.\n", 10788c2ecf20Sopenharmony_ci __func__, 'A' + layer); 10798c2ecf20Sopenharmony_ci return -EBUSY; 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci /* Read Packet error Count */ 10838c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xb9 + layer * 2); 10848c2ecf20Sopenharmony_ci if (rc < 0) 10858c2ecf20Sopenharmony_ci return rc; 10868c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 10878c2ecf20Sopenharmony_ci if (rc < 0) 10888c2ecf20Sopenharmony_ci return rc; 10898c2ecf20Sopenharmony_ci *error = rc << 8; 10908c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xba + layer * 2); 10918c2ecf20Sopenharmony_ci if (rc < 0) 10928c2ecf20Sopenharmony_ci return rc; 10938c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 10948c2ecf20Sopenharmony_ci if (rc < 0) 10958c2ecf20Sopenharmony_ci return rc; 10968c2ecf20Sopenharmony_ci *error |= rc; 10978c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s: block error for layer %c: %d.\n", 10988c2ecf20Sopenharmony_ci __func__, 'A' + layer, *error); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci /* Read Bit Count */ 11018c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xb2 + layer * 2); 11028c2ecf20Sopenharmony_ci if (rc < 0) 11038c2ecf20Sopenharmony_ci return rc; 11048c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 11058c2ecf20Sopenharmony_ci if (rc < 0) 11068c2ecf20Sopenharmony_ci return rc; 11078c2ecf20Sopenharmony_ci *count = rc << 8; 11088c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xb3 + layer * 2); 11098c2ecf20Sopenharmony_ci if (rc < 0) 11108c2ecf20Sopenharmony_ci return rc; 11118c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 11128c2ecf20Sopenharmony_ci if (rc < 0) 11138c2ecf20Sopenharmony_ci return rc; 11148c2ecf20Sopenharmony_ci *count |= rc; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 11178c2ecf20Sopenharmony_ci "%s: block count for layer %c: %d.\n", 11188c2ecf20Sopenharmony_ci __func__, 'A' + layer, *count); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci /* 11218c2ecf20Sopenharmony_ci * As we get TMCC data from the frontend, we can better estimate the 11228c2ecf20Sopenharmony_ci * BER bit counters, in order to do the BER measure during a longer 11238c2ecf20Sopenharmony_ci * time. Use those data, if available, to update the bit count 11248c2ecf20Sopenharmony_ci * measure. 11258c2ecf20Sopenharmony_ci */ 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci if (!state->estimated_rate[layer]) 11288c2ecf20Sopenharmony_ci goto reset_measurement; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci collect_rate = state->estimated_rate[layer] / 204 / 8; 11318c2ecf20Sopenharmony_ci if (collect_rate < 32) 11328c2ecf20Sopenharmony_ci collect_rate = 32; 11338c2ecf20Sopenharmony_ci if (collect_rate > 65535) 11348c2ecf20Sopenharmony_ci collect_rate = 65535; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if (collect_rate != *count) { 11378c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 11388c2ecf20Sopenharmony_ci "%s: updating PER counter on layer %c to %d.\n", 11398c2ecf20Sopenharmony_ci __func__, 'A' + layer, collect_rate); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci /* Stop PER measurement */ 11428c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xb0); 11438c2ecf20Sopenharmony_ci if (rc < 0) 11448c2ecf20Sopenharmony_ci return rc; 11458c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, 0x00); 11468c2ecf20Sopenharmony_ci if (rc < 0) 11478c2ecf20Sopenharmony_ci return rc; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci /* Update this layer's counter */ 11508c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xb2 + layer * 2); 11518c2ecf20Sopenharmony_ci if (rc < 0) 11528c2ecf20Sopenharmony_ci return rc; 11538c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, collect_rate >> 8); 11548c2ecf20Sopenharmony_ci if (rc < 0) 11558c2ecf20Sopenharmony_ci return rc; 11568c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xb3 + layer * 2); 11578c2ecf20Sopenharmony_ci if (rc < 0) 11588c2ecf20Sopenharmony_ci return rc; 11598c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, collect_rate & 0xff); 11608c2ecf20Sopenharmony_ci if (rc < 0) 11618c2ecf20Sopenharmony_ci return rc; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci /* start PER measurement */ 11648c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xb0); 11658c2ecf20Sopenharmony_ci if (rc < 0) 11668c2ecf20Sopenharmony_ci return rc; 11678c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, 0x07); 11688c2ecf20Sopenharmony_ci if (rc < 0) 11698c2ecf20Sopenharmony_ci return rc; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci /* Reset all counters to collect new data */ 11728c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xb1); 11738c2ecf20Sopenharmony_ci if (rc < 0) 11748c2ecf20Sopenharmony_ci return rc; 11758c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, 0x07); 11768c2ecf20Sopenharmony_ci if (rc < 0) 11778c2ecf20Sopenharmony_ci return rc; 11788c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, 0x00); 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci return rc; 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_cireset_measurement: 11848c2ecf20Sopenharmony_ci /* Reset counter to collect new data */ 11858c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xb1); 11868c2ecf20Sopenharmony_ci if (rc < 0) 11878c2ecf20Sopenharmony_ci return rc; 11888c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 11898c2ecf20Sopenharmony_ci if (rc < 0) 11908c2ecf20Sopenharmony_ci return rc; 11918c2ecf20Sopenharmony_ci val = rc; 11928c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, val | (1 << layer)); 11938c2ecf20Sopenharmony_ci if (rc < 0) 11948c2ecf20Sopenharmony_ci return rc; 11958c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, val & ~(1 << layer)); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci return rc; 11988c2ecf20Sopenharmony_ci} 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_cistruct linear_segments { 12018c2ecf20Sopenharmony_ci unsigned x, y; 12028c2ecf20Sopenharmony_ci}; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci/* 12058c2ecf20Sopenharmony_ci * All tables below return a dB/1000 measurement 12068c2ecf20Sopenharmony_ci */ 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_cistatic const struct linear_segments cnr_to_db_table[] = { 12098c2ecf20Sopenharmony_ci { 19648, 0}, 12108c2ecf20Sopenharmony_ci { 18187, 1000}, 12118c2ecf20Sopenharmony_ci { 16534, 2000}, 12128c2ecf20Sopenharmony_ci { 14823, 3000}, 12138c2ecf20Sopenharmony_ci { 13161, 4000}, 12148c2ecf20Sopenharmony_ci { 11622, 5000}, 12158c2ecf20Sopenharmony_ci { 10279, 6000}, 12168c2ecf20Sopenharmony_ci { 9089, 7000}, 12178c2ecf20Sopenharmony_ci { 8042, 8000}, 12188c2ecf20Sopenharmony_ci { 7137, 9000}, 12198c2ecf20Sopenharmony_ci { 6342, 10000}, 12208c2ecf20Sopenharmony_ci { 5641, 11000}, 12218c2ecf20Sopenharmony_ci { 5030, 12000}, 12228c2ecf20Sopenharmony_ci { 4474, 13000}, 12238c2ecf20Sopenharmony_ci { 3988, 14000}, 12248c2ecf20Sopenharmony_ci { 3556, 15000}, 12258c2ecf20Sopenharmony_ci { 3180, 16000}, 12268c2ecf20Sopenharmony_ci { 2841, 17000}, 12278c2ecf20Sopenharmony_ci { 2541, 18000}, 12288c2ecf20Sopenharmony_ci { 2276, 19000}, 12298c2ecf20Sopenharmony_ci { 2038, 20000}, 12308c2ecf20Sopenharmony_ci { 1800, 21000}, 12318c2ecf20Sopenharmony_ci { 1625, 22000}, 12328c2ecf20Sopenharmony_ci { 1462, 23000}, 12338c2ecf20Sopenharmony_ci { 1324, 24000}, 12348c2ecf20Sopenharmony_ci { 1175, 25000}, 12358c2ecf20Sopenharmony_ci { 1063, 26000}, 12368c2ecf20Sopenharmony_ci { 980, 27000}, 12378c2ecf20Sopenharmony_ci { 907, 28000}, 12388c2ecf20Sopenharmony_ci { 840, 29000}, 12398c2ecf20Sopenharmony_ci { 788, 30000}, 12408c2ecf20Sopenharmony_ci}; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_cistatic const struct linear_segments cnr_64qam_table[] = { 12438c2ecf20Sopenharmony_ci { 3922688, 0}, 12448c2ecf20Sopenharmony_ci { 3920384, 1000}, 12458c2ecf20Sopenharmony_ci { 3902720, 2000}, 12468c2ecf20Sopenharmony_ci { 3894784, 3000}, 12478c2ecf20Sopenharmony_ci { 3882496, 4000}, 12488c2ecf20Sopenharmony_ci { 3872768, 5000}, 12498c2ecf20Sopenharmony_ci { 3858944, 6000}, 12508c2ecf20Sopenharmony_ci { 3851520, 7000}, 12518c2ecf20Sopenharmony_ci { 3838976, 8000}, 12528c2ecf20Sopenharmony_ci { 3829248, 9000}, 12538c2ecf20Sopenharmony_ci { 3818240, 10000}, 12548c2ecf20Sopenharmony_ci { 3806976, 11000}, 12558c2ecf20Sopenharmony_ci { 3791872, 12000}, 12568c2ecf20Sopenharmony_ci { 3767040, 13000}, 12578c2ecf20Sopenharmony_ci { 3720960, 14000}, 12588c2ecf20Sopenharmony_ci { 3637504, 15000}, 12598c2ecf20Sopenharmony_ci { 3498496, 16000}, 12608c2ecf20Sopenharmony_ci { 3296000, 17000}, 12618c2ecf20Sopenharmony_ci { 3031040, 18000}, 12628c2ecf20Sopenharmony_ci { 2715392, 19000}, 12638c2ecf20Sopenharmony_ci { 2362624, 20000}, 12648c2ecf20Sopenharmony_ci { 1963264, 21000}, 12658c2ecf20Sopenharmony_ci { 1649664, 22000}, 12668c2ecf20Sopenharmony_ci { 1366784, 23000}, 12678c2ecf20Sopenharmony_ci { 1120768, 24000}, 12688c2ecf20Sopenharmony_ci { 890880, 25000}, 12698c2ecf20Sopenharmony_ci { 723456, 26000}, 12708c2ecf20Sopenharmony_ci { 612096, 27000}, 12718c2ecf20Sopenharmony_ci { 518912, 28000}, 12728c2ecf20Sopenharmony_ci { 448256, 29000}, 12738c2ecf20Sopenharmony_ci { 388864, 30000}, 12748c2ecf20Sopenharmony_ci}; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_cistatic const struct linear_segments cnr_16qam_table[] = { 12778c2ecf20Sopenharmony_ci { 5314816, 0}, 12788c2ecf20Sopenharmony_ci { 5219072, 1000}, 12798c2ecf20Sopenharmony_ci { 5118720, 2000}, 12808c2ecf20Sopenharmony_ci { 4998912, 3000}, 12818c2ecf20Sopenharmony_ci { 4875520, 4000}, 12828c2ecf20Sopenharmony_ci { 4736000, 5000}, 12838c2ecf20Sopenharmony_ci { 4604160, 6000}, 12848c2ecf20Sopenharmony_ci { 4458752, 7000}, 12858c2ecf20Sopenharmony_ci { 4300288, 8000}, 12868c2ecf20Sopenharmony_ci { 4092928, 9000}, 12878c2ecf20Sopenharmony_ci { 3836160, 10000}, 12888c2ecf20Sopenharmony_ci { 3521024, 11000}, 12898c2ecf20Sopenharmony_ci { 3155968, 12000}, 12908c2ecf20Sopenharmony_ci { 2756864, 13000}, 12918c2ecf20Sopenharmony_ci { 2347008, 14000}, 12928c2ecf20Sopenharmony_ci { 1955072, 15000}, 12938c2ecf20Sopenharmony_ci { 1593600, 16000}, 12948c2ecf20Sopenharmony_ci { 1297920, 17000}, 12958c2ecf20Sopenharmony_ci { 1043968, 18000}, 12968c2ecf20Sopenharmony_ci { 839680, 19000}, 12978c2ecf20Sopenharmony_ci { 672256, 20000}, 12988c2ecf20Sopenharmony_ci { 523008, 21000}, 12998c2ecf20Sopenharmony_ci { 424704, 22000}, 13008c2ecf20Sopenharmony_ci { 345088, 23000}, 13018c2ecf20Sopenharmony_ci { 280064, 24000}, 13028c2ecf20Sopenharmony_ci { 221440, 25000}, 13038c2ecf20Sopenharmony_ci { 179712, 26000}, 13048c2ecf20Sopenharmony_ci { 151040, 27000}, 13058c2ecf20Sopenharmony_ci { 128512, 28000}, 13068c2ecf20Sopenharmony_ci { 110080, 29000}, 13078c2ecf20Sopenharmony_ci { 95744, 30000}, 13088c2ecf20Sopenharmony_ci}; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_cistatic const struct linear_segments cnr_qpsk_table[] = { 13118c2ecf20Sopenharmony_ci { 2834176, 0}, 13128c2ecf20Sopenharmony_ci { 2683648, 1000}, 13138c2ecf20Sopenharmony_ci { 2536960, 2000}, 13148c2ecf20Sopenharmony_ci { 2391808, 3000}, 13158c2ecf20Sopenharmony_ci { 2133248, 4000}, 13168c2ecf20Sopenharmony_ci { 1906176, 5000}, 13178c2ecf20Sopenharmony_ci { 1666560, 6000}, 13188c2ecf20Sopenharmony_ci { 1422080, 7000}, 13198c2ecf20Sopenharmony_ci { 1189632, 8000}, 13208c2ecf20Sopenharmony_ci { 976384, 9000}, 13218c2ecf20Sopenharmony_ci { 790272, 10000}, 13228c2ecf20Sopenharmony_ci { 633344, 11000}, 13238c2ecf20Sopenharmony_ci { 505600, 12000}, 13248c2ecf20Sopenharmony_ci { 402944, 13000}, 13258c2ecf20Sopenharmony_ci { 320768, 14000}, 13268c2ecf20Sopenharmony_ci { 255488, 15000}, 13278c2ecf20Sopenharmony_ci { 204032, 16000}, 13288c2ecf20Sopenharmony_ci { 163072, 17000}, 13298c2ecf20Sopenharmony_ci { 130304, 18000}, 13308c2ecf20Sopenharmony_ci { 105216, 19000}, 13318c2ecf20Sopenharmony_ci { 83456, 20000}, 13328c2ecf20Sopenharmony_ci { 65024, 21000}, 13338c2ecf20Sopenharmony_ci { 52480, 22000}, 13348c2ecf20Sopenharmony_ci { 42752, 23000}, 13358c2ecf20Sopenharmony_ci { 34560, 24000}, 13368c2ecf20Sopenharmony_ci { 27136, 25000}, 13378c2ecf20Sopenharmony_ci { 22016, 26000}, 13388c2ecf20Sopenharmony_ci { 18432, 27000}, 13398c2ecf20Sopenharmony_ci { 15616, 28000}, 13408c2ecf20Sopenharmony_ci { 13312, 29000}, 13418c2ecf20Sopenharmony_ci { 11520, 30000}, 13428c2ecf20Sopenharmony_ci}; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_cistatic u32 interpolate_value(u32 value, const struct linear_segments *segments, 13458c2ecf20Sopenharmony_ci unsigned len) 13468c2ecf20Sopenharmony_ci{ 13478c2ecf20Sopenharmony_ci u64 tmp64; 13488c2ecf20Sopenharmony_ci u32 dx, dy; 13498c2ecf20Sopenharmony_ci int i, ret; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci if (value >= segments[0].x) 13528c2ecf20Sopenharmony_ci return segments[0].y; 13538c2ecf20Sopenharmony_ci if (value < segments[len-1].x) 13548c2ecf20Sopenharmony_ci return segments[len-1].y; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci for (i = 1; i < len - 1; i++) { 13578c2ecf20Sopenharmony_ci /* If value is identical, no need to interpolate */ 13588c2ecf20Sopenharmony_ci if (value == segments[i].x) 13598c2ecf20Sopenharmony_ci return segments[i].y; 13608c2ecf20Sopenharmony_ci if (value > segments[i].x) 13618c2ecf20Sopenharmony_ci break; 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci /* Linear interpolation between the two (x,y) points */ 13658c2ecf20Sopenharmony_ci dy = segments[i].y - segments[i - 1].y; 13668c2ecf20Sopenharmony_ci dx = segments[i - 1].x - segments[i].x; 13678c2ecf20Sopenharmony_ci tmp64 = value - segments[i].x; 13688c2ecf20Sopenharmony_ci tmp64 *= dy; 13698c2ecf20Sopenharmony_ci do_div(tmp64, dx); 13708c2ecf20Sopenharmony_ci ret = segments[i].y - tmp64; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci return ret; 13738c2ecf20Sopenharmony_ci} 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_cistatic int mb86a20s_get_main_CNR(struct dvb_frontend *fe) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 13788c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 13798c2ecf20Sopenharmony_ci u32 cnr_linear, cnr; 13808c2ecf20Sopenharmony_ci int rc, val; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci /* Check if CNR is available */ 13838c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x45); 13848c2ecf20Sopenharmony_ci if (rc < 0) 13858c2ecf20Sopenharmony_ci return rc; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci if (!(rc & 0x40)) { 13888c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s: CNR is not available yet.\n", 13898c2ecf20Sopenharmony_ci __func__); 13908c2ecf20Sopenharmony_ci return -EBUSY; 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci val = rc; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x46); 13958c2ecf20Sopenharmony_ci if (rc < 0) 13968c2ecf20Sopenharmony_ci return rc; 13978c2ecf20Sopenharmony_ci cnr_linear = rc << 8; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x46); 14008c2ecf20Sopenharmony_ci if (rc < 0) 14018c2ecf20Sopenharmony_ci return rc; 14028c2ecf20Sopenharmony_ci cnr_linear |= rc; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci cnr = interpolate_value(cnr_linear, 14058c2ecf20Sopenharmony_ci cnr_to_db_table, ARRAY_SIZE(cnr_to_db_table)); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 14088c2ecf20Sopenharmony_ci c->cnr.stat[0].svalue = cnr; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s: CNR is %d.%03d dB (%d)\n", 14118c2ecf20Sopenharmony_ci __func__, cnr / 1000, cnr % 1000, cnr_linear); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci /* CNR counter reset */ 14148c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x45, val | 0x10); 14158c2ecf20Sopenharmony_ci if (rc < 0) 14168c2ecf20Sopenharmony_ci return rc; 14178c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x45, val & 0x6f); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci return rc; 14208c2ecf20Sopenharmony_ci} 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_cistatic int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe) 14238c2ecf20Sopenharmony_ci{ 14248c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 14258c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 14268c2ecf20Sopenharmony_ci u32 mer, cnr; 14278c2ecf20Sopenharmony_ci int rc, val, layer; 14288c2ecf20Sopenharmony_ci const struct linear_segments *segs; 14298c2ecf20Sopenharmony_ci unsigned segs_len; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci /* Check if the measures are already available */ 14348c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0x5b); 14358c2ecf20Sopenharmony_ci if (rc < 0) 14368c2ecf20Sopenharmony_ci return rc; 14378c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 14388c2ecf20Sopenharmony_ci if (rc < 0) 14398c2ecf20Sopenharmony_ci return rc; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci /* Check if data is available */ 14428c2ecf20Sopenharmony_ci if (!(rc & 0x01)) { 14438c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 14448c2ecf20Sopenharmony_ci "%s: MER measures aren't available yet.\n", __func__); 14458c2ecf20Sopenharmony_ci return -EBUSY; 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci /* Read all layers */ 14498c2ecf20Sopenharmony_ci for (layer = 0; layer < NUM_LAYERS; layer++) { 14508c2ecf20Sopenharmony_ci if (!(c->isdbt_layer_enabled & (1 << layer))) { 14518c2ecf20Sopenharmony_ci c->cnr.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 14528c2ecf20Sopenharmony_ci continue; 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0x52 + layer * 3); 14568c2ecf20Sopenharmony_ci if (rc < 0) 14578c2ecf20Sopenharmony_ci return rc; 14588c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 14598c2ecf20Sopenharmony_ci if (rc < 0) 14608c2ecf20Sopenharmony_ci return rc; 14618c2ecf20Sopenharmony_ci mer = rc << 16; 14628c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0x53 + layer * 3); 14638c2ecf20Sopenharmony_ci if (rc < 0) 14648c2ecf20Sopenharmony_ci return rc; 14658c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 14668c2ecf20Sopenharmony_ci if (rc < 0) 14678c2ecf20Sopenharmony_ci return rc; 14688c2ecf20Sopenharmony_ci mer |= rc << 8; 14698c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0x54 + layer * 3); 14708c2ecf20Sopenharmony_ci if (rc < 0) 14718c2ecf20Sopenharmony_ci return rc; 14728c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 14738c2ecf20Sopenharmony_ci if (rc < 0) 14748c2ecf20Sopenharmony_ci return rc; 14758c2ecf20Sopenharmony_ci mer |= rc; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci switch (c->layer[layer].modulation) { 14788c2ecf20Sopenharmony_ci case DQPSK: 14798c2ecf20Sopenharmony_ci case QPSK: 14808c2ecf20Sopenharmony_ci segs = cnr_qpsk_table; 14818c2ecf20Sopenharmony_ci segs_len = ARRAY_SIZE(cnr_qpsk_table); 14828c2ecf20Sopenharmony_ci break; 14838c2ecf20Sopenharmony_ci case QAM_16: 14848c2ecf20Sopenharmony_ci segs = cnr_16qam_table; 14858c2ecf20Sopenharmony_ci segs_len = ARRAY_SIZE(cnr_16qam_table); 14868c2ecf20Sopenharmony_ci break; 14878c2ecf20Sopenharmony_ci default: 14888c2ecf20Sopenharmony_ci case QAM_64: 14898c2ecf20Sopenharmony_ci segs = cnr_64qam_table; 14908c2ecf20Sopenharmony_ci segs_len = ARRAY_SIZE(cnr_64qam_table); 14918c2ecf20Sopenharmony_ci break; 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci cnr = interpolate_value(mer, segs, segs_len); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci c->cnr.stat[1 + layer].scale = FE_SCALE_DECIBEL; 14968c2ecf20Sopenharmony_ci c->cnr.stat[1 + layer].svalue = cnr; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, 14998c2ecf20Sopenharmony_ci "%s: CNR for layer %c is %d.%03d dB (MER = %d).\n", 15008c2ecf20Sopenharmony_ci __func__, 'A' + layer, cnr / 1000, cnr % 1000, mer); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci /* Start a new MER measurement */ 15058c2ecf20Sopenharmony_ci /* MER counter reset */ 15068c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0x50); 15078c2ecf20Sopenharmony_ci if (rc < 0) 15088c2ecf20Sopenharmony_ci return rc; 15098c2ecf20Sopenharmony_ci rc = mb86a20s_readreg(state, 0x51); 15108c2ecf20Sopenharmony_ci if (rc < 0) 15118c2ecf20Sopenharmony_ci return rc; 15128c2ecf20Sopenharmony_ci val = rc; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, val | 0x01); 15158c2ecf20Sopenharmony_ci if (rc < 0) 15168c2ecf20Sopenharmony_ci return rc; 15178c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, val & 0x06); 15188c2ecf20Sopenharmony_ci if (rc < 0) 15198c2ecf20Sopenharmony_ci return rc; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci return 0; 15228c2ecf20Sopenharmony_ci} 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_cistatic void mb86a20s_stats_not_ready(struct dvb_frontend *fe) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 15278c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 15288c2ecf20Sopenharmony_ci int layer; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci /* Fill the length of each status counter */ 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci /* Only global stats */ 15358c2ecf20Sopenharmony_ci c->strength.len = 1; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci /* Per-layer stats - 3 layers + global */ 15388c2ecf20Sopenharmony_ci c->cnr.len = NUM_LAYERS + 1; 15398c2ecf20Sopenharmony_ci c->pre_bit_error.len = NUM_LAYERS + 1; 15408c2ecf20Sopenharmony_ci c->pre_bit_count.len = NUM_LAYERS + 1; 15418c2ecf20Sopenharmony_ci c->post_bit_error.len = NUM_LAYERS + 1; 15428c2ecf20Sopenharmony_ci c->post_bit_count.len = NUM_LAYERS + 1; 15438c2ecf20Sopenharmony_ci c->block_error.len = NUM_LAYERS + 1; 15448c2ecf20Sopenharmony_ci c->block_count.len = NUM_LAYERS + 1; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci /* Signal is always available */ 15478c2ecf20Sopenharmony_ci c->strength.stat[0].scale = FE_SCALE_RELATIVE; 15488c2ecf20Sopenharmony_ci c->strength.stat[0].uvalue = 0; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci /* Put all of them at FE_SCALE_NOT_AVAILABLE */ 15518c2ecf20Sopenharmony_ci for (layer = 0; layer < NUM_LAYERS + 1; layer++) { 15528c2ecf20Sopenharmony_ci c->cnr.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 15538c2ecf20Sopenharmony_ci c->pre_bit_error.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 15548c2ecf20Sopenharmony_ci c->pre_bit_count.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 15558c2ecf20Sopenharmony_ci c->post_bit_error.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 15568c2ecf20Sopenharmony_ci c->post_bit_count.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 15578c2ecf20Sopenharmony_ci c->block_error.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 15588c2ecf20Sopenharmony_ci c->block_count.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_cistatic int mb86a20s_get_stats(struct dvb_frontend *fe, int status_nr) 15638c2ecf20Sopenharmony_ci{ 15648c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 15658c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 15668c2ecf20Sopenharmony_ci int rc = 0, layer; 15678c2ecf20Sopenharmony_ci u32 bit_error = 0, bit_count = 0; 15688c2ecf20Sopenharmony_ci u32 t_pre_bit_error = 0, t_pre_bit_count = 0; 15698c2ecf20Sopenharmony_ci u32 t_post_bit_error = 0, t_post_bit_count = 0; 15708c2ecf20Sopenharmony_ci u32 block_error = 0, block_count = 0; 15718c2ecf20Sopenharmony_ci u32 t_block_error = 0, t_block_count = 0; 15728c2ecf20Sopenharmony_ci int active_layers = 0, pre_ber_layers = 0, post_ber_layers = 0; 15738c2ecf20Sopenharmony_ci int per_layers = 0; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci mb86a20s_get_main_CNR(fe); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci /* Get per-layer stats */ 15808c2ecf20Sopenharmony_ci mb86a20s_get_blk_error_layer_CNR(fe); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci /* 15838c2ecf20Sopenharmony_ci * At state 7, only CNR is available 15848c2ecf20Sopenharmony_ci * For BER measures, state=9 is required 15858c2ecf20Sopenharmony_ci * FIXME: we may get MER measures with state=8 15868c2ecf20Sopenharmony_ci */ 15878c2ecf20Sopenharmony_ci if (status_nr < 9) 15888c2ecf20Sopenharmony_ci return 0; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci for (layer = 0; layer < NUM_LAYERS; layer++) { 15918c2ecf20Sopenharmony_ci if (c->isdbt_layer_enabled & (1 << layer)) { 15928c2ecf20Sopenharmony_ci /* Layer is active and has rc segments */ 15938c2ecf20Sopenharmony_ci active_layers++; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci /* Handle BER before vterbi */ 15968c2ecf20Sopenharmony_ci rc = mb86a20s_get_pre_ber(fe, layer, 15978c2ecf20Sopenharmony_ci &bit_error, &bit_count); 15988c2ecf20Sopenharmony_ci if (rc >= 0) { 15998c2ecf20Sopenharmony_ci c->pre_bit_error.stat[1 + layer].scale = FE_SCALE_COUNTER; 16008c2ecf20Sopenharmony_ci c->pre_bit_error.stat[1 + layer].uvalue += bit_error; 16018c2ecf20Sopenharmony_ci c->pre_bit_count.stat[1 + layer].scale = FE_SCALE_COUNTER; 16028c2ecf20Sopenharmony_ci c->pre_bit_count.stat[1 + layer].uvalue += bit_count; 16038c2ecf20Sopenharmony_ci } else if (rc != -EBUSY) { 16048c2ecf20Sopenharmony_ci /* 16058c2ecf20Sopenharmony_ci * If an I/O error happened, 16068c2ecf20Sopenharmony_ci * measures are now unavailable 16078c2ecf20Sopenharmony_ci */ 16088c2ecf20Sopenharmony_ci c->pre_bit_error.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 16098c2ecf20Sopenharmony_ci c->pre_bit_count.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 16108c2ecf20Sopenharmony_ci dev_err(&state->i2c->dev, 16118c2ecf20Sopenharmony_ci "%s: Can't get BER for layer %c (error %d).\n", 16128c2ecf20Sopenharmony_ci __func__, 'A' + layer, rc); 16138c2ecf20Sopenharmony_ci } 16148c2ecf20Sopenharmony_ci if (c->block_error.stat[1 + layer].scale != FE_SCALE_NOT_AVAILABLE) 16158c2ecf20Sopenharmony_ci pre_ber_layers++; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci /* Handle BER post vterbi */ 16188c2ecf20Sopenharmony_ci rc = mb86a20s_get_post_ber(fe, layer, 16198c2ecf20Sopenharmony_ci &bit_error, &bit_count); 16208c2ecf20Sopenharmony_ci if (rc >= 0) { 16218c2ecf20Sopenharmony_ci c->post_bit_error.stat[1 + layer].scale = FE_SCALE_COUNTER; 16228c2ecf20Sopenharmony_ci c->post_bit_error.stat[1 + layer].uvalue += bit_error; 16238c2ecf20Sopenharmony_ci c->post_bit_count.stat[1 + layer].scale = FE_SCALE_COUNTER; 16248c2ecf20Sopenharmony_ci c->post_bit_count.stat[1 + layer].uvalue += bit_count; 16258c2ecf20Sopenharmony_ci } else if (rc != -EBUSY) { 16268c2ecf20Sopenharmony_ci /* 16278c2ecf20Sopenharmony_ci * If an I/O error happened, 16288c2ecf20Sopenharmony_ci * measures are now unavailable 16298c2ecf20Sopenharmony_ci */ 16308c2ecf20Sopenharmony_ci c->post_bit_error.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 16318c2ecf20Sopenharmony_ci c->post_bit_count.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 16328c2ecf20Sopenharmony_ci dev_err(&state->i2c->dev, 16338c2ecf20Sopenharmony_ci "%s: Can't get BER for layer %c (error %d).\n", 16348c2ecf20Sopenharmony_ci __func__, 'A' + layer, rc); 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci if (c->block_error.stat[1 + layer].scale != FE_SCALE_NOT_AVAILABLE) 16378c2ecf20Sopenharmony_ci post_ber_layers++; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci /* Handle Block errors for PER/UCB reports */ 16408c2ecf20Sopenharmony_ci rc = mb86a20s_get_blk_error(fe, layer, 16418c2ecf20Sopenharmony_ci &block_error, 16428c2ecf20Sopenharmony_ci &block_count); 16438c2ecf20Sopenharmony_ci if (rc >= 0) { 16448c2ecf20Sopenharmony_ci c->block_error.stat[1 + layer].scale = FE_SCALE_COUNTER; 16458c2ecf20Sopenharmony_ci c->block_error.stat[1 + layer].uvalue += block_error; 16468c2ecf20Sopenharmony_ci c->block_count.stat[1 + layer].scale = FE_SCALE_COUNTER; 16478c2ecf20Sopenharmony_ci c->block_count.stat[1 + layer].uvalue += block_count; 16488c2ecf20Sopenharmony_ci } else if (rc != -EBUSY) { 16498c2ecf20Sopenharmony_ci /* 16508c2ecf20Sopenharmony_ci * If an I/O error happened, 16518c2ecf20Sopenharmony_ci * measures are now unavailable 16528c2ecf20Sopenharmony_ci */ 16538c2ecf20Sopenharmony_ci c->block_error.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 16548c2ecf20Sopenharmony_ci c->block_count.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 16558c2ecf20Sopenharmony_ci dev_err(&state->i2c->dev, 16568c2ecf20Sopenharmony_ci "%s: Can't get PER for layer %c (error %d).\n", 16578c2ecf20Sopenharmony_ci __func__, 'A' + layer, rc); 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci } 16608c2ecf20Sopenharmony_ci if (c->block_error.stat[1 + layer].scale != FE_SCALE_NOT_AVAILABLE) 16618c2ecf20Sopenharmony_ci per_layers++; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci /* Update total preBER */ 16648c2ecf20Sopenharmony_ci t_pre_bit_error += c->pre_bit_error.stat[1 + layer].uvalue; 16658c2ecf20Sopenharmony_ci t_pre_bit_count += c->pre_bit_count.stat[1 + layer].uvalue; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci /* Update total postBER */ 16688c2ecf20Sopenharmony_ci t_post_bit_error += c->post_bit_error.stat[1 + layer].uvalue; 16698c2ecf20Sopenharmony_ci t_post_bit_count += c->post_bit_count.stat[1 + layer].uvalue; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci /* Update total PER */ 16728c2ecf20Sopenharmony_ci t_block_error += c->block_error.stat[1 + layer].uvalue; 16738c2ecf20Sopenharmony_ci t_block_count += c->block_count.stat[1 + layer].uvalue; 16748c2ecf20Sopenharmony_ci } 16758c2ecf20Sopenharmony_ci } 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci /* 16788c2ecf20Sopenharmony_ci * Start showing global count if at least one error count is 16798c2ecf20Sopenharmony_ci * available. 16808c2ecf20Sopenharmony_ci */ 16818c2ecf20Sopenharmony_ci if (pre_ber_layers) { 16828c2ecf20Sopenharmony_ci /* 16838c2ecf20Sopenharmony_ci * At least one per-layer BER measure was read. We can now 16848c2ecf20Sopenharmony_ci * calculate the total BER 16858c2ecf20Sopenharmony_ci * 16868c2ecf20Sopenharmony_ci * Total Bit Error/Count is calculated as the sum of the 16878c2ecf20Sopenharmony_ci * bit errors on all active layers. 16888c2ecf20Sopenharmony_ci */ 16898c2ecf20Sopenharmony_ci c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; 16908c2ecf20Sopenharmony_ci c->pre_bit_error.stat[0].uvalue = t_pre_bit_error; 16918c2ecf20Sopenharmony_ci c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; 16928c2ecf20Sopenharmony_ci c->pre_bit_count.stat[0].uvalue = t_pre_bit_count; 16938c2ecf20Sopenharmony_ci } else { 16948c2ecf20Sopenharmony_ci c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 16958c2ecf20Sopenharmony_ci c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci /* 16998c2ecf20Sopenharmony_ci * Start showing global count if at least one error count is 17008c2ecf20Sopenharmony_ci * available. 17018c2ecf20Sopenharmony_ci */ 17028c2ecf20Sopenharmony_ci if (post_ber_layers) { 17038c2ecf20Sopenharmony_ci /* 17048c2ecf20Sopenharmony_ci * At least one per-layer BER measure was read. We can now 17058c2ecf20Sopenharmony_ci * calculate the total BER 17068c2ecf20Sopenharmony_ci * 17078c2ecf20Sopenharmony_ci * Total Bit Error/Count is calculated as the sum of the 17088c2ecf20Sopenharmony_ci * bit errors on all active layers. 17098c2ecf20Sopenharmony_ci */ 17108c2ecf20Sopenharmony_ci c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; 17118c2ecf20Sopenharmony_ci c->post_bit_error.stat[0].uvalue = t_post_bit_error; 17128c2ecf20Sopenharmony_ci c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; 17138c2ecf20Sopenharmony_ci c->post_bit_count.stat[0].uvalue = t_post_bit_count; 17148c2ecf20Sopenharmony_ci } else { 17158c2ecf20Sopenharmony_ci c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 17168c2ecf20Sopenharmony_ci c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci if (per_layers) { 17208c2ecf20Sopenharmony_ci /* 17218c2ecf20Sopenharmony_ci * At least one per-layer UCB measure was read. We can now 17228c2ecf20Sopenharmony_ci * calculate the total UCB 17238c2ecf20Sopenharmony_ci * 17248c2ecf20Sopenharmony_ci * Total block Error/Count is calculated as the sum of the 17258c2ecf20Sopenharmony_ci * block errors on all active layers. 17268c2ecf20Sopenharmony_ci */ 17278c2ecf20Sopenharmony_ci c->block_error.stat[0].scale = FE_SCALE_COUNTER; 17288c2ecf20Sopenharmony_ci c->block_error.stat[0].uvalue = t_block_error; 17298c2ecf20Sopenharmony_ci c->block_count.stat[0].scale = FE_SCALE_COUNTER; 17308c2ecf20Sopenharmony_ci c->block_count.stat[0].uvalue = t_block_count; 17318c2ecf20Sopenharmony_ci } else { 17328c2ecf20Sopenharmony_ci c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 17338c2ecf20Sopenharmony_ci c->block_count.stat[0].scale = FE_SCALE_COUNTER; 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci return rc; 17378c2ecf20Sopenharmony_ci} 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci/* 17408c2ecf20Sopenharmony_ci * The functions below are called via DVB callbacks, so they need to 17418c2ecf20Sopenharmony_ci * properly use the I2C gate control 17428c2ecf20Sopenharmony_ci */ 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_cistatic int mb86a20s_initfe(struct dvb_frontend *fe) 17458c2ecf20Sopenharmony_ci{ 17468c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 17478c2ecf20Sopenharmony_ci u64 pll; 17488c2ecf20Sopenharmony_ci u32 fclk; 17498c2ecf20Sopenharmony_ci int rc; 17508c2ecf20Sopenharmony_ci u8 regD5 = 1, reg71, reg09 = 0x3a; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 17558c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci /* Initialize the frontend */ 17588c2ecf20Sopenharmony_ci rc = mb86a20s_writeregdata(state, mb86a20s_init1); 17598c2ecf20Sopenharmony_ci if (rc < 0) 17608c2ecf20Sopenharmony_ci goto err; 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci if (!state->inversion) 17638c2ecf20Sopenharmony_ci reg09 |= 0x04; 17648c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x09, reg09); 17658c2ecf20Sopenharmony_ci if (rc < 0) 17668c2ecf20Sopenharmony_ci goto err; 17678c2ecf20Sopenharmony_ci if (!state->bw) 17688c2ecf20Sopenharmony_ci reg71 = 1; 17698c2ecf20Sopenharmony_ci else 17708c2ecf20Sopenharmony_ci reg71 = 0; 17718c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x39, reg71); 17728c2ecf20Sopenharmony_ci if (rc < 0) 17738c2ecf20Sopenharmony_ci goto err; 17748c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x71, state->bw); 17758c2ecf20Sopenharmony_ci if (rc < 0) 17768c2ecf20Sopenharmony_ci goto err; 17778c2ecf20Sopenharmony_ci if (state->subchannel) { 17788c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x44, state->subchannel); 17798c2ecf20Sopenharmony_ci if (rc < 0) 17808c2ecf20Sopenharmony_ci goto err; 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci fclk = state->config->fclk; 17848c2ecf20Sopenharmony_ci if (!fclk) 17858c2ecf20Sopenharmony_ci fclk = 32571428; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci /* Adjust IF frequency to match tuner */ 17888c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.get_if_frequency) 17898c2ecf20Sopenharmony_ci fe->ops.tuner_ops.get_if_frequency(fe, &state->if_freq); 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci if (!state->if_freq) 17928c2ecf20Sopenharmony_ci state->if_freq = 3300000; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci pll = (((u64)1) << 34) * state->if_freq; 17958c2ecf20Sopenharmony_ci do_div(pll, 63 * fclk); 17968c2ecf20Sopenharmony_ci pll = (1 << 25) - pll; 17978c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x28, 0x2a); 17988c2ecf20Sopenharmony_ci if (rc < 0) 17998c2ecf20Sopenharmony_ci goto err; 18008c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x29, (pll >> 16) & 0xff); 18018c2ecf20Sopenharmony_ci if (rc < 0) 18028c2ecf20Sopenharmony_ci goto err; 18038c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x2a, (pll >> 8) & 0xff); 18048c2ecf20Sopenharmony_ci if (rc < 0) 18058c2ecf20Sopenharmony_ci goto err; 18068c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x2b, pll & 0xff); 18078c2ecf20Sopenharmony_ci if (rc < 0) 18088c2ecf20Sopenharmony_ci goto err; 18098c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s: fclk=%d, IF=%d, clock reg=0x%06llx\n", 18108c2ecf20Sopenharmony_ci __func__, fclk, state->if_freq, (long long)pll); 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci /* pll = freq[Hz] * 2^24/10^6 / 16.285714286 */ 18138c2ecf20Sopenharmony_ci pll = state->if_freq * 1677721600L; 18148c2ecf20Sopenharmony_ci do_div(pll, 1628571429L); 18158c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x28, 0x20); 18168c2ecf20Sopenharmony_ci if (rc < 0) 18178c2ecf20Sopenharmony_ci goto err; 18188c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x29, (pll >> 16) & 0xff); 18198c2ecf20Sopenharmony_ci if (rc < 0) 18208c2ecf20Sopenharmony_ci goto err; 18218c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x2a, (pll >> 8) & 0xff); 18228c2ecf20Sopenharmony_ci if (rc < 0) 18238c2ecf20Sopenharmony_ci goto err; 18248c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x2b, pll & 0xff); 18258c2ecf20Sopenharmony_ci if (rc < 0) 18268c2ecf20Sopenharmony_ci goto err; 18278c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s: IF=%d, IF reg=0x%06llx\n", 18288c2ecf20Sopenharmony_ci __func__, state->if_freq, (long long)pll); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci if (!state->config->is_serial) 18318c2ecf20Sopenharmony_ci regD5 &= ~1; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x50, 0xd5); 18348c2ecf20Sopenharmony_ci if (rc < 0) 18358c2ecf20Sopenharmony_ci goto err; 18368c2ecf20Sopenharmony_ci rc = mb86a20s_writereg(state, 0x51, regD5); 18378c2ecf20Sopenharmony_ci if (rc < 0) 18388c2ecf20Sopenharmony_ci goto err; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci rc = mb86a20s_writeregdata(state, mb86a20s_init2); 18418c2ecf20Sopenharmony_ci if (rc < 0) 18428c2ecf20Sopenharmony_ci goto err; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_cierr: 18468c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 18478c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci if (rc < 0) { 18508c2ecf20Sopenharmony_ci state->need_init = true; 18518c2ecf20Sopenharmony_ci dev_info(&state->i2c->dev, 18528c2ecf20Sopenharmony_ci "mb86a20s: Init failed. Will try again later\n"); 18538c2ecf20Sopenharmony_ci } else { 18548c2ecf20Sopenharmony_ci state->need_init = false; 18558c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "Initialization succeeded.\n"); 18568c2ecf20Sopenharmony_ci } 18578c2ecf20Sopenharmony_ci return rc; 18588c2ecf20Sopenharmony_ci} 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_cistatic int mb86a20s_set_frontend(struct dvb_frontend *fe) 18618c2ecf20Sopenharmony_ci{ 18628c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 18638c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 18648c2ecf20Sopenharmony_ci int rc, if_freq; 18658c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci if (!c->isdbt_layer_enabled) 18688c2ecf20Sopenharmony_ci c->isdbt_layer_enabled = 7; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci if (c->isdbt_layer_enabled == 1) 18718c2ecf20Sopenharmony_ci state->bw = MB86A20S_1SEG; 18728c2ecf20Sopenharmony_ci else if (c->isdbt_partial_reception) 18738c2ecf20Sopenharmony_ci state->bw = MB86A20S_13SEG_PARTIAL; 18748c2ecf20Sopenharmony_ci else 18758c2ecf20Sopenharmony_ci state->bw = MB86A20S_13SEG; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci if (c->inversion == INVERSION_ON) 18788c2ecf20Sopenharmony_ci state->inversion = true; 18798c2ecf20Sopenharmony_ci else 18808c2ecf20Sopenharmony_ci state->inversion = false; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci if (!c->isdbt_sb_mode) { 18838c2ecf20Sopenharmony_ci state->subchannel = 0; 18848c2ecf20Sopenharmony_ci } else { 18858c2ecf20Sopenharmony_ci if (c->isdbt_sb_subchannel >= ARRAY_SIZE(mb86a20s_subchannel)) 18868c2ecf20Sopenharmony_ci c->isdbt_sb_subchannel = 0; 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci state->subchannel = mb86a20s_subchannel[c->isdbt_sb_subchannel]; 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci /* 18928c2ecf20Sopenharmony_ci * Gate should already be opened, but it doesn't hurt to 18938c2ecf20Sopenharmony_ci * double-check 18948c2ecf20Sopenharmony_ci */ 18958c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 18968c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 18978c2ecf20Sopenharmony_ci fe->ops.tuner_ops.set_params(fe); 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.get_if_frequency) 19008c2ecf20Sopenharmony_ci fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci /* 19038c2ecf20Sopenharmony_ci * Make it more reliable: if, for some reason, the initial 19048c2ecf20Sopenharmony_ci * device initialization doesn't happen, initialize it when 19058c2ecf20Sopenharmony_ci * a SBTVD parameters are adjusted. 19068c2ecf20Sopenharmony_ci * 19078c2ecf20Sopenharmony_ci * Unfortunately, due to a hard to track bug at tda829x/tda18271, 19088c2ecf20Sopenharmony_ci * the agc callback logic is not called during DVB attach time, 19098c2ecf20Sopenharmony_ci * causing mb86a20s to not be initialized with Kworld SBTVD. 19108c2ecf20Sopenharmony_ci * So, this hack is needed, in order to make Kworld SBTVD to work. 19118c2ecf20Sopenharmony_ci * 19128c2ecf20Sopenharmony_ci * It is also needed to change the IF after the initial init. 19138c2ecf20Sopenharmony_ci * 19148c2ecf20Sopenharmony_ci * HACK: Always init the frontend when set_frontend is called: 19158c2ecf20Sopenharmony_ci * it was noticed that, on some devices, it fails to lock on a 19168c2ecf20Sopenharmony_ci * different channel. So, it is better to reset everything, even 19178c2ecf20Sopenharmony_ci * wasting some time, than to loose channel lock. 19188c2ecf20Sopenharmony_ci */ 19198c2ecf20Sopenharmony_ci mb86a20s_initfe(fe); 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 19228c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception); 19258c2ecf20Sopenharmony_ci mb86a20s_reset_counters(fe); 19268c2ecf20Sopenharmony_ci mb86a20s_stats_not_ready(fe); 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 19298c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci return rc; 19328c2ecf20Sopenharmony_ci} 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_cistatic int mb86a20s_read_status_and_stats(struct dvb_frontend *fe, 19358c2ecf20Sopenharmony_ci enum fe_status *status) 19368c2ecf20Sopenharmony_ci{ 19378c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 19388c2ecf20Sopenharmony_ci int rc, status_nr; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 19438c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci /* Get lock */ 19468c2ecf20Sopenharmony_ci status_nr = mb86a20s_read_status(fe, status); 19478c2ecf20Sopenharmony_ci if (status_nr < 7) { 19488c2ecf20Sopenharmony_ci mb86a20s_stats_not_ready(fe); 19498c2ecf20Sopenharmony_ci mb86a20s_reset_frontend_cache(fe); 19508c2ecf20Sopenharmony_ci } 19518c2ecf20Sopenharmony_ci if (status_nr < 0) { 19528c2ecf20Sopenharmony_ci dev_err(&state->i2c->dev, 19538c2ecf20Sopenharmony_ci "%s: Can't read frontend lock status\n", __func__); 19548c2ecf20Sopenharmony_ci rc = status_nr; 19558c2ecf20Sopenharmony_ci goto error; 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci /* Get signal strength */ 19598c2ecf20Sopenharmony_ci rc = mb86a20s_read_signal_strength(fe); 19608c2ecf20Sopenharmony_ci if (rc < 0) { 19618c2ecf20Sopenharmony_ci dev_err(&state->i2c->dev, 19628c2ecf20Sopenharmony_ci "%s: Can't reset VBER registers.\n", __func__); 19638c2ecf20Sopenharmony_ci mb86a20s_stats_not_ready(fe); 19648c2ecf20Sopenharmony_ci mb86a20s_reset_frontend_cache(fe); 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci rc = 0; /* Status is OK */ 19678c2ecf20Sopenharmony_ci goto error; 19688c2ecf20Sopenharmony_ci } 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci if (status_nr >= 7) { 19718c2ecf20Sopenharmony_ci /* Get TMCC info*/ 19728c2ecf20Sopenharmony_ci rc = mb86a20s_get_frontend(fe); 19738c2ecf20Sopenharmony_ci if (rc < 0) { 19748c2ecf20Sopenharmony_ci dev_err(&state->i2c->dev, 19758c2ecf20Sopenharmony_ci "%s: Can't get FE TMCC data.\n", __func__); 19768c2ecf20Sopenharmony_ci rc = 0; /* Status is OK */ 19778c2ecf20Sopenharmony_ci goto error; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci /* Get statistics */ 19818c2ecf20Sopenharmony_ci rc = mb86a20s_get_stats(fe, status_nr); 19828c2ecf20Sopenharmony_ci if (rc < 0 && rc != -EBUSY) { 19838c2ecf20Sopenharmony_ci dev_err(&state->i2c->dev, 19848c2ecf20Sopenharmony_ci "%s: Can't get FE statistics.\n", __func__); 19858c2ecf20Sopenharmony_ci rc = 0; 19868c2ecf20Sopenharmony_ci goto error; 19878c2ecf20Sopenharmony_ci } 19888c2ecf20Sopenharmony_ci rc = 0; /* Don't return EBUSY to userspace */ 19898c2ecf20Sopenharmony_ci } 19908c2ecf20Sopenharmony_ci goto ok; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_cierror: 19938c2ecf20Sopenharmony_ci mb86a20s_stats_not_ready(fe); 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ciok: 19968c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 19978c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci return rc; 20008c2ecf20Sopenharmony_ci} 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_cistatic int mb86a20s_read_signal_strength_from_cache(struct dvb_frontend *fe, 20038c2ecf20Sopenharmony_ci u16 *strength) 20048c2ecf20Sopenharmony_ci{ 20058c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci *strength = c->strength.stat[0].uvalue; 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci return 0; 20118c2ecf20Sopenharmony_ci} 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_cistatic int mb86a20s_tune(struct dvb_frontend *fe, 20148c2ecf20Sopenharmony_ci bool re_tune, 20158c2ecf20Sopenharmony_ci unsigned int mode_flags, 20168c2ecf20Sopenharmony_ci unsigned int *delay, 20178c2ecf20Sopenharmony_ci enum fe_status *status) 20188c2ecf20Sopenharmony_ci{ 20198c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 20208c2ecf20Sopenharmony_ci int rc = 0; 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci if (re_tune) 20258c2ecf20Sopenharmony_ci rc = mb86a20s_set_frontend(fe); 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) 20288c2ecf20Sopenharmony_ci mb86a20s_read_status_and_stats(fe, status); 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci return rc; 20318c2ecf20Sopenharmony_ci} 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_cistatic void mb86a20s_release(struct dvb_frontend *fe) 20348c2ecf20Sopenharmony_ci{ 20358c2ecf20Sopenharmony_ci struct mb86a20s_state *state = fe->demodulator_priv; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci kfree(state); 20408c2ecf20Sopenharmony_ci} 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_cistatic enum dvbfe_algo mb86a20s_get_frontend_algo(struct dvb_frontend *fe) 20438c2ecf20Sopenharmony_ci{ 20448c2ecf20Sopenharmony_ci return DVBFE_ALGO_HW; 20458c2ecf20Sopenharmony_ci} 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops mb86a20s_ops; 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_cistruct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, 20508c2ecf20Sopenharmony_ci struct i2c_adapter *i2c) 20518c2ecf20Sopenharmony_ci{ 20528c2ecf20Sopenharmony_ci struct mb86a20s_state *state; 20538c2ecf20Sopenharmony_ci u8 rev; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci dev_dbg(&i2c->dev, "%s called.\n", __func__); 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci /* allocate memory for the internal state */ 20588c2ecf20Sopenharmony_ci state = kzalloc(sizeof(*state), GFP_KERNEL); 20598c2ecf20Sopenharmony_ci if (!state) 20608c2ecf20Sopenharmony_ci return NULL; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci /* setup the state */ 20638c2ecf20Sopenharmony_ci state->config = config; 20648c2ecf20Sopenharmony_ci state->i2c = i2c; 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci /* create dvb_frontend */ 20678c2ecf20Sopenharmony_ci memcpy(&state->frontend.ops, &mb86a20s_ops, 20688c2ecf20Sopenharmony_ci sizeof(struct dvb_frontend_ops)); 20698c2ecf20Sopenharmony_ci state->frontend.demodulator_priv = state; 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci /* Check if it is a mb86a20s frontend */ 20728c2ecf20Sopenharmony_ci rev = mb86a20s_readreg(state, 0); 20738c2ecf20Sopenharmony_ci if (rev != 0x13) { 20748c2ecf20Sopenharmony_ci kfree(state); 20758c2ecf20Sopenharmony_ci dev_dbg(&i2c->dev, 20768c2ecf20Sopenharmony_ci "Frontend revision %d is unknown - aborting.\n", 20778c2ecf20Sopenharmony_ci rev); 20788c2ecf20Sopenharmony_ci return NULL; 20798c2ecf20Sopenharmony_ci } 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci dev_info(&i2c->dev, "Detected a Fujitsu mb86a20s frontend\n"); 20828c2ecf20Sopenharmony_ci return &state->frontend; 20838c2ecf20Sopenharmony_ci} 20848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mb86a20s_attach); 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops mb86a20s_ops = { 20878c2ecf20Sopenharmony_ci .delsys = { SYS_ISDBT }, 20888c2ecf20Sopenharmony_ci /* Use dib8000 values per default */ 20898c2ecf20Sopenharmony_ci .info = { 20908c2ecf20Sopenharmony_ci .name = "Fujitsu mb86A20s", 20918c2ecf20Sopenharmony_ci .caps = FE_CAN_RECOVER | 20928c2ecf20Sopenharmony_ci FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 20938c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 20948c2ecf20Sopenharmony_ci FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | 20958c2ecf20Sopenharmony_ci FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_QAM_AUTO | 20968c2ecf20Sopenharmony_ci FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, 20978c2ecf20Sopenharmony_ci /* Actually, those values depend on the used tuner */ 20988c2ecf20Sopenharmony_ci .frequency_min_hz = 45 * MHz, 20998c2ecf20Sopenharmony_ci .frequency_max_hz = 864 * MHz, 21008c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 62500, 21018c2ecf20Sopenharmony_ci }, 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci .release = mb86a20s_release, 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci .init = mb86a20s_initfe, 21068c2ecf20Sopenharmony_ci .set_frontend = mb86a20s_set_frontend, 21078c2ecf20Sopenharmony_ci .read_status = mb86a20s_read_status_and_stats, 21088c2ecf20Sopenharmony_ci .read_signal_strength = mb86a20s_read_signal_strength_from_cache, 21098c2ecf20Sopenharmony_ci .tune = mb86a20s_tune, 21108c2ecf20Sopenharmony_ci .get_frontend_algo = mb86a20s_get_frontend_algo, 21118c2ecf20Sopenharmony_ci}; 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware"); 21148c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mauro Carvalho Chehab"); 21158c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2116