150acfb2bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 29a0bf528SMauro Carvalho Chehab /* 39a0bf528SMauro Carvalho Chehab * Fujitu mb86a20s ISDB-T/ISDB-Tsb Module driver 49a0bf528SMauro Carvalho Chehab * 537e59f87SMauro Carvalho Chehab * Copyright (C) 2010-2013 Mauro Carvalho Chehab 69a0bf528SMauro Carvalho Chehab * Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com> 79a0bf528SMauro Carvalho Chehab */ 89a0bf528SMauro Carvalho Chehab 99a0bf528SMauro Carvalho Chehab #include <linux/kernel.h> 109a0bf528SMauro Carvalho Chehab #include <asm/div64.h> 119a0bf528SMauro Carvalho Chehab 12fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h> 139a0bf528SMauro Carvalho Chehab #include "mb86a20s.h" 149a0bf528SMauro Carvalho Chehab 154f62a20dSMauro Carvalho Chehab #define NUM_LAYERS 3 164f62a20dSMauro Carvalho Chehab 1704fa725eSMauro Carvalho Chehab enum mb86a20s_bandwidth { 1804fa725eSMauro Carvalho Chehab MB86A20S_13SEG = 0, 1904fa725eSMauro Carvalho Chehab MB86A20S_13SEG_PARTIAL = 1, 2004fa725eSMauro Carvalho Chehab MB86A20S_1SEG = 2, 2104fa725eSMauro Carvalho Chehab MB86A20S_3SEG = 3, 2204fa725eSMauro Carvalho Chehab }; 2304fa725eSMauro Carvalho Chehab 24ce08131cSHans Verkuil static u8 mb86a20s_subchannel[] = { 2504fa725eSMauro Carvalho Chehab 0xb0, 0xc0, 0xd0, 0xe0, 2604fa725eSMauro Carvalho Chehab 0xf0, 0x00, 0x10, 0x20, 2704fa725eSMauro Carvalho Chehab }; 2804fa725eSMauro Carvalho Chehab 299a0bf528SMauro Carvalho Chehab struct mb86a20s_state { 309a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c; 319a0bf528SMauro Carvalho Chehab const struct mb86a20s_config *config; 3209b6d21eSMauro Carvalho Chehab u32 last_frequency; 339a0bf528SMauro Carvalho Chehab 349a0bf528SMauro Carvalho Chehab struct dvb_frontend frontend; 359a0bf528SMauro Carvalho Chehab 36768e6dadSMauro Carvalho Chehab u32 if_freq; 3704fa725eSMauro Carvalho Chehab enum mb86a20s_bandwidth bw; 3804fa725eSMauro Carvalho Chehab bool inversion; 3904fa725eSMauro Carvalho Chehab u32 subchannel; 40768e6dadSMauro Carvalho Chehab 414f62a20dSMauro Carvalho Chehab u32 estimated_rate[NUM_LAYERS]; 420921ecfdSMauro Carvalho Chehab unsigned long get_strength_time; 43d01a8ee3SMauro Carvalho Chehab 449a0bf528SMauro Carvalho Chehab bool need_init; 459a0bf528SMauro Carvalho Chehab }; 469a0bf528SMauro Carvalho Chehab 479a0bf528SMauro Carvalho Chehab struct regdata { 489a0bf528SMauro Carvalho Chehab u8 reg; 499a0bf528SMauro Carvalho Chehab u8 data; 509a0bf528SMauro Carvalho Chehab }; 519a0bf528SMauro Carvalho Chehab 52d01a8ee3SMauro Carvalho Chehab #define BER_SAMPLING_RATE 1 /* Seconds */ 53d01a8ee3SMauro Carvalho Chehab 549a0bf528SMauro Carvalho Chehab /* 559a0bf528SMauro Carvalho Chehab * Initialization sequence: Use whatevere default values that PV SBTVD 569a0bf528SMauro Carvalho Chehab * does on its initialisation, obtained via USB snoop 579a0bf528SMauro Carvalho Chehab */ 58768e6dadSMauro Carvalho Chehab static struct regdata mb86a20s_init1[] = { 599a0bf528SMauro Carvalho Chehab { 0x70, 0x0f }, 609a0bf528SMauro Carvalho Chehab { 0x70, 0xff }, 619a0bf528SMauro Carvalho Chehab { 0x08, 0x01 }, 6217e67d4cSMauro Carvalho Chehab { 0x50, 0xd1 }, { 0x51, 0x20 }, 63768e6dadSMauro Carvalho Chehab }; 64768e6dadSMauro Carvalho Chehab 65768e6dadSMauro Carvalho Chehab static struct regdata mb86a20s_init2[] = { 66505a0ea7SMauro Carvalho Chehab { 0x50, 0xd1 }, { 0x51, 0x22 }, 67505a0ea7SMauro Carvalho Chehab { 0x39, 0x01 }, 68505a0ea7SMauro Carvalho Chehab { 0x71, 0x00 }, 699a0bf528SMauro Carvalho Chehab { 0x3b, 0x21 }, 70505a0ea7SMauro Carvalho Chehab { 0x3c, 0x3a }, 719a0bf528SMauro Carvalho Chehab { 0x01, 0x0d }, 72505a0ea7SMauro Carvalho Chehab { 0x04, 0x08 }, { 0x05, 0x05 }, 739a0bf528SMauro Carvalho Chehab { 0x04, 0x0e }, { 0x05, 0x00 }, 74505a0ea7SMauro Carvalho Chehab { 0x04, 0x0f }, { 0x05, 0x14 }, 75505a0ea7SMauro Carvalho Chehab { 0x04, 0x0b }, { 0x05, 0x8c }, 769a0bf528SMauro Carvalho Chehab { 0x04, 0x00 }, { 0x05, 0x00 }, 77505a0ea7SMauro Carvalho Chehab { 0x04, 0x01 }, { 0x05, 0x07 }, 78505a0ea7SMauro Carvalho Chehab { 0x04, 0x02 }, { 0x05, 0x0f }, 79505a0ea7SMauro Carvalho Chehab { 0x04, 0x03 }, { 0x05, 0xa0 }, 809a0bf528SMauro Carvalho Chehab { 0x04, 0x09 }, { 0x05, 0x00 }, 819a0bf528SMauro Carvalho Chehab { 0x04, 0x0a }, { 0x05, 0xff }, 82505a0ea7SMauro Carvalho Chehab { 0x04, 0x27 }, { 0x05, 0x64 }, 839a0bf528SMauro Carvalho Chehab { 0x04, 0x28 }, { 0x05, 0x00 }, 84505a0ea7SMauro Carvalho Chehab { 0x04, 0x1e }, { 0x05, 0xff }, 85505a0ea7SMauro Carvalho Chehab { 0x04, 0x29 }, { 0x05, 0x0a }, 86505a0ea7SMauro Carvalho Chehab { 0x04, 0x32 }, { 0x05, 0x0a }, 879a0bf528SMauro Carvalho Chehab { 0x04, 0x14 }, { 0x05, 0x02 }, 889a0bf528SMauro Carvalho Chehab { 0x04, 0x04 }, { 0x05, 0x00 }, 899a0bf528SMauro Carvalho Chehab { 0x04, 0x05 }, { 0x05, 0x22 }, 909a0bf528SMauro Carvalho Chehab { 0x04, 0x06 }, { 0x05, 0x0e }, 919a0bf528SMauro Carvalho Chehab { 0x04, 0x07 }, { 0x05, 0xd8 }, 929a0bf528SMauro Carvalho Chehab { 0x04, 0x12 }, { 0x05, 0x00 }, 939a0bf528SMauro Carvalho Chehab { 0x04, 0x13 }, { 0x05, 0xff }, 9409b6d21eSMauro Carvalho Chehab 9509b6d21eSMauro Carvalho Chehab /* 9609b6d21eSMauro Carvalho Chehab * On this demod, when the bit count reaches the count below, 9709b6d21eSMauro Carvalho Chehab * it collects the bit error count. The bit counters are initialized 9809b6d21eSMauro Carvalho Chehab * to 65535 here. This warrants that all of them will be quickly 9909b6d21eSMauro Carvalho Chehab * calculated when device gets locked. As TMCC is parsed, the values 100d01a8ee3SMauro Carvalho Chehab * will be adjusted later in the driver's code. 10109b6d21eSMauro Carvalho Chehab */ 10209b6d21eSMauro Carvalho Chehab { 0x52, 0x01 }, /* Turn on BER before Viterbi */ 10309b6d21eSMauro Carvalho Chehab { 0x50, 0xa7 }, { 0x51, 0x00 }, 1049a0bf528SMauro Carvalho Chehab { 0x50, 0xa8 }, { 0x51, 0xff }, 1059a0bf528SMauro Carvalho Chehab { 0x50, 0xa9 }, { 0x51, 0xff }, 10609b6d21eSMauro Carvalho Chehab { 0x50, 0xaa }, { 0x51, 0x00 }, 1079a0bf528SMauro Carvalho Chehab { 0x50, 0xab }, { 0x51, 0xff }, 1089a0bf528SMauro Carvalho Chehab { 0x50, 0xac }, { 0x51, 0xff }, 10909b6d21eSMauro Carvalho Chehab { 0x50, 0xad }, { 0x51, 0x00 }, 1109a0bf528SMauro Carvalho Chehab { 0x50, 0xae }, { 0x51, 0xff }, 1119a0bf528SMauro Carvalho Chehab { 0x50, 0xaf }, { 0x51, 0xff }, 11209b6d21eSMauro Carvalho Chehab 113d9b6f08aSMauro Carvalho Chehab /* 114d9b6f08aSMauro Carvalho Chehab * On this demod, post BER counts blocks. When the count reaches the 115d9b6f08aSMauro Carvalho Chehab * value below, it collects the block error count. The block counters 116d9b6f08aSMauro Carvalho Chehab * are initialized to 127 here. This warrants that all of them will be 117d9b6f08aSMauro Carvalho Chehab * quickly calculated when device gets locked. As TMCC is parsed, the 118d9b6f08aSMauro Carvalho Chehab * values will be adjusted later in the driver's code. 119d9b6f08aSMauro Carvalho Chehab */ 120d9b6f08aSMauro Carvalho Chehab { 0x5e, 0x07 }, /* Turn on BER after Viterbi */ 121d9b6f08aSMauro Carvalho Chehab { 0x50, 0xdc }, { 0x51, 0x00 }, 122d9b6f08aSMauro Carvalho Chehab { 0x50, 0xdd }, { 0x51, 0x7f }, 123d9b6f08aSMauro Carvalho Chehab { 0x50, 0xde }, { 0x51, 0x00 }, 124d9b6f08aSMauro Carvalho Chehab { 0x50, 0xdf }, { 0x51, 0x7f }, 125d9b6f08aSMauro Carvalho Chehab { 0x50, 0xe0 }, { 0x51, 0x00 }, 126d9b6f08aSMauro Carvalho Chehab { 0x50, 0xe1 }, { 0x51, 0x7f }, 127593ae89aSMauro Carvalho Chehab 128593ae89aSMauro Carvalho Chehab /* 129593ae89aSMauro Carvalho Chehab * On this demod, when the block count reaches the count below, 130593ae89aSMauro Carvalho Chehab * it collects the block error count. The block counters are initialized 131593ae89aSMauro Carvalho Chehab * to 127 here. This warrants that all of them will be quickly 132593ae89aSMauro Carvalho Chehab * calculated when device gets locked. As TMCC is parsed, the values 133593ae89aSMauro Carvalho Chehab * will be adjusted later in the driver's code. 134593ae89aSMauro Carvalho Chehab */ 135593ae89aSMauro Carvalho Chehab { 0x50, 0xb0 }, { 0x51, 0x07 }, /* Enable PER */ 136593ae89aSMauro Carvalho Chehab { 0x50, 0xb2 }, { 0x51, 0x00 }, 137593ae89aSMauro Carvalho Chehab { 0x50, 0xb3 }, { 0x51, 0x7f }, 138593ae89aSMauro Carvalho Chehab { 0x50, 0xb4 }, { 0x51, 0x00 }, 139593ae89aSMauro Carvalho Chehab { 0x50, 0xb5 }, { 0x51, 0x7f }, 140593ae89aSMauro Carvalho Chehab { 0x50, 0xb6 }, { 0x51, 0x00 }, 141593ae89aSMauro Carvalho Chehab { 0x50, 0xb7 }, { 0x51, 0x7f }, 14225188bd0SMauro Carvalho Chehab 14325188bd0SMauro Carvalho Chehab { 0x50, 0x50 }, { 0x51, 0x02 }, /* MER manual mode */ 14409b6d21eSMauro Carvalho Chehab { 0x50, 0x51 }, { 0x51, 0x04 }, /* MER symbol 4 */ 14509b6d21eSMauro Carvalho Chehab { 0x45, 0x04 }, /* CN symbol 4 */ 14625188bd0SMauro Carvalho Chehab { 0x48, 0x04 }, /* CN manual mode */ 147505a0ea7SMauro Carvalho Chehab { 0x50, 0xd5 }, { 0x51, 0x01 }, 1489a0bf528SMauro Carvalho Chehab { 0x50, 0xd6 }, { 0x51, 0x1f }, 1499a0bf528SMauro Carvalho Chehab { 0x50, 0xd2 }, { 0x51, 0x03 }, 150505a0ea7SMauro Carvalho Chehab { 0x50, 0xd7 }, { 0x51, 0x3f }, 1519a0bf528SMauro Carvalho Chehab { 0x1c, 0x01 }, 152505a0ea7SMauro Carvalho Chehab { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x03 }, 153505a0ea7SMauro Carvalho Chehab { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0d }, 154505a0ea7SMauro Carvalho Chehab { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 }, 155505a0ea7SMauro Carvalho Chehab { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x01 }, 156505a0ea7SMauro Carvalho Chehab { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x21 }, 157505a0ea7SMauro Carvalho Chehab { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x29 }, 158505a0ea7SMauro Carvalho Chehab { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 }, 159505a0ea7SMauro Carvalho Chehab { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x31 }, 160505a0ea7SMauro Carvalho Chehab { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0e }, 161505a0ea7SMauro Carvalho Chehab { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x4e }, 162505a0ea7SMauro Carvalho Chehab { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x46 }, 163505a0ea7SMauro Carvalho Chehab { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f }, 164505a0ea7SMauro Carvalho Chehab { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x56 }, 165505a0ea7SMauro Carvalho Chehab { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x35 }, 166505a0ea7SMauro Carvalho Chehab { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbe }, 167505a0ea7SMauro Carvalho Chehab { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0x84 }, 168505a0ea7SMauro Carvalho Chehab { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x03 }, { 0x2b, 0xee }, 169505a0ea7SMauro Carvalho Chehab { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x98 }, 170505a0ea7SMauro Carvalho Chehab { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x9f }, 171505a0ea7SMauro Carvalho Chehab { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xb2 }, 172505a0ea7SMauro Carvalho Chehab { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0xc2 }, 173505a0ea7SMauro Carvalho Chehab { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0x4a }, 174505a0ea7SMauro Carvalho Chehab { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbc }, 175505a0ea7SMauro Carvalho Chehab { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x04 }, { 0x2b, 0xba }, 176505a0ea7SMauro Carvalho Chehab { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0x14 }, 1779a0bf528SMauro Carvalho Chehab { 0x50, 0x1e }, { 0x51, 0x5d }, 1789a0bf528SMauro Carvalho Chehab { 0x50, 0x22 }, { 0x51, 0x00 }, 1799a0bf528SMauro Carvalho Chehab { 0x50, 0x23 }, { 0x51, 0xc8 }, 1809a0bf528SMauro Carvalho Chehab { 0x50, 0x24 }, { 0x51, 0x00 }, 1819a0bf528SMauro Carvalho Chehab { 0x50, 0x25 }, { 0x51, 0xf0 }, 1829a0bf528SMauro Carvalho Chehab { 0x50, 0x26 }, { 0x51, 0x00 }, 1839a0bf528SMauro Carvalho Chehab { 0x50, 0x27 }, { 0x51, 0xc3 }, 1849a0bf528SMauro Carvalho Chehab { 0x50, 0x39 }, { 0x51, 0x02 }, 185505a0ea7SMauro Carvalho Chehab { 0x50, 0xd5 }, { 0x51, 0x01 }, 1869a0bf528SMauro Carvalho Chehab { 0xd0, 0x00 }, 1879a0bf528SMauro Carvalho Chehab }; 1889a0bf528SMauro Carvalho Chehab 1899a0bf528SMauro Carvalho Chehab static struct regdata mb86a20s_reset_reception[] = { 1909a0bf528SMauro Carvalho Chehab { 0x70, 0xf0 }, 1919a0bf528SMauro Carvalho Chehab { 0x70, 0xff }, 1929a0bf528SMauro Carvalho Chehab { 0x08, 0x01 }, 1939a0bf528SMauro Carvalho Chehab { 0x08, 0x00 }, 1949a0bf528SMauro Carvalho Chehab }; 1959a0bf528SMauro Carvalho Chehab 196d9b6f08aSMauro Carvalho Chehab static struct regdata mb86a20s_per_ber_reset[] = { 197d9b6f08aSMauro Carvalho Chehab { 0x53, 0x00 }, /* pre BER Counter reset */ 19809b6d21eSMauro Carvalho Chehab { 0x53, 0x07 }, 19909b6d21eSMauro Carvalho Chehab 200d9b6f08aSMauro Carvalho Chehab { 0x5f, 0x00 }, /* post BER Counter reset */ 201d9b6f08aSMauro Carvalho Chehab { 0x5f, 0x07 }, 202d9b6f08aSMauro Carvalho Chehab 20309b6d21eSMauro Carvalho Chehab { 0x50, 0xb1 }, /* PER Counter reset */ 20409b6d21eSMauro Carvalho Chehab { 0x51, 0x07 }, 20509b6d21eSMauro Carvalho Chehab { 0x51, 0x00 }, 20609b6d21eSMauro Carvalho Chehab }; 20709b6d21eSMauro Carvalho Chehab 208dd4493efSMauro Carvalho Chehab /* 209dd4493efSMauro Carvalho Chehab * I2C read/write functions and macros 210dd4493efSMauro Carvalho Chehab */ 211dd4493efSMauro Carvalho Chehab 2129a0bf528SMauro Carvalho Chehab static int mb86a20s_i2c_writereg(struct mb86a20s_state *state, 21309b6d21eSMauro Carvalho Chehab u8 i2c_addr, u8 reg, u8 data) 2149a0bf528SMauro Carvalho Chehab { 2159a0bf528SMauro Carvalho Chehab u8 buf[] = { reg, data }; 2169a0bf528SMauro Carvalho Chehab struct i2c_msg msg = { 2179a0bf528SMauro Carvalho Chehab .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2 2189a0bf528SMauro Carvalho Chehab }; 2199a0bf528SMauro Carvalho Chehab int rc; 2209a0bf528SMauro Carvalho Chehab 2219a0bf528SMauro Carvalho Chehab rc = i2c_transfer(state->i2c, &msg, 1); 2229a0bf528SMauro Carvalho Chehab if (rc != 1) { 223f66d81b5SMauro Carvalho Chehab dev_err(&state->i2c->dev, 224f66d81b5SMauro Carvalho Chehab "%s: writereg error (rc == %i, reg == 0x%02x, data == 0x%02x)\n", 225f66d81b5SMauro Carvalho Chehab __func__, rc, reg, data); 2269a0bf528SMauro Carvalho Chehab return rc; 2279a0bf528SMauro Carvalho Chehab } 2289a0bf528SMauro Carvalho Chehab 2299a0bf528SMauro Carvalho Chehab return 0; 2309a0bf528SMauro Carvalho Chehab } 2319a0bf528SMauro Carvalho Chehab 2329a0bf528SMauro Carvalho Chehab static int mb86a20s_i2c_writeregdata(struct mb86a20s_state *state, 2339a0bf528SMauro Carvalho Chehab u8 i2c_addr, struct regdata *rd, int size) 2349a0bf528SMauro Carvalho Chehab { 2359a0bf528SMauro Carvalho Chehab int i, rc; 2369a0bf528SMauro Carvalho Chehab 2379a0bf528SMauro Carvalho Chehab for (i = 0; i < size; i++) { 2389a0bf528SMauro Carvalho Chehab rc = mb86a20s_i2c_writereg(state, i2c_addr, rd[i].reg, 2399a0bf528SMauro Carvalho Chehab rd[i].data); 2409a0bf528SMauro Carvalho Chehab if (rc < 0) 2419a0bf528SMauro Carvalho Chehab return rc; 2429a0bf528SMauro Carvalho Chehab } 2439a0bf528SMauro Carvalho Chehab return 0; 2449a0bf528SMauro Carvalho Chehab } 2459a0bf528SMauro Carvalho Chehab 2469a0bf528SMauro Carvalho Chehab static int mb86a20s_i2c_readreg(struct mb86a20s_state *state, 2479a0bf528SMauro Carvalho Chehab u8 i2c_addr, u8 reg) 2489a0bf528SMauro Carvalho Chehab { 2499a0bf528SMauro Carvalho Chehab u8 val; 2509a0bf528SMauro Carvalho Chehab int rc; 2519a0bf528SMauro Carvalho Chehab struct i2c_msg msg[] = { 2529a0bf528SMauro Carvalho Chehab { .addr = i2c_addr, .flags = 0, .buf = ®, .len = 1 }, 2539a0bf528SMauro Carvalho Chehab { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 } 2549a0bf528SMauro Carvalho Chehab }; 2559a0bf528SMauro Carvalho Chehab 2569a0bf528SMauro Carvalho Chehab rc = i2c_transfer(state->i2c, msg, 2); 2579a0bf528SMauro Carvalho Chehab 2589a0bf528SMauro Carvalho Chehab if (rc != 2) { 259f66d81b5SMauro Carvalho Chehab dev_err(&state->i2c->dev, "%s: reg=0x%x (error=%d)\n", 260f66d81b5SMauro Carvalho Chehab __func__, reg, rc); 261f66d81b5SMauro Carvalho Chehab return (rc < 0) ? rc : -EIO; 2629a0bf528SMauro Carvalho Chehab } 2639a0bf528SMauro Carvalho Chehab 2649a0bf528SMauro Carvalho Chehab return val; 2659a0bf528SMauro Carvalho Chehab } 2669a0bf528SMauro Carvalho Chehab 2679a0bf528SMauro Carvalho Chehab #define mb86a20s_readreg(state, reg) \ 2689a0bf528SMauro Carvalho Chehab mb86a20s_i2c_readreg(state, state->config->demod_address, reg) 2699a0bf528SMauro Carvalho Chehab #define mb86a20s_writereg(state, reg, val) \ 2709a0bf528SMauro Carvalho Chehab mb86a20s_i2c_writereg(state, state->config->demod_address, reg, val) 2719a0bf528SMauro Carvalho Chehab #define mb86a20s_writeregdata(state, regdata) \ 2729a0bf528SMauro Carvalho Chehab mb86a20s_i2c_writeregdata(state, state->config->demod_address, \ 2739a0bf528SMauro Carvalho Chehab regdata, ARRAY_SIZE(regdata)) 2749a0bf528SMauro Carvalho Chehab 27509b6d21eSMauro Carvalho Chehab /* 27609b6d21eSMauro Carvalho Chehab * Ancillary internal routines (likely compiled inlined) 27709b6d21eSMauro Carvalho Chehab * 27809b6d21eSMauro Carvalho Chehab * The functions below assume that gateway lock has already obtained 27909b6d21eSMauro Carvalho Chehab */ 28009b6d21eSMauro Carvalho Chehab 2810df289a2SMauro Carvalho Chehab static int mb86a20s_read_status(struct dvb_frontend *fe, enum fe_status *status) 2829a0bf528SMauro Carvalho Chehab { 2839a0bf528SMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 284dd4493efSMauro Carvalho Chehab int val; 2859a0bf528SMauro Carvalho Chehab 286dd4493efSMauro Carvalho Chehab *status = 0; 2879a0bf528SMauro Carvalho Chehab 288eca2d34bSColin Ian King val = mb86a20s_readreg(state, 0x0a); 289dd4493efSMauro Carvalho Chehab if (val < 0) 290dd4493efSMauro Carvalho Chehab return val; 2919a0bf528SMauro Carvalho Chehab 292eca2d34bSColin Ian King val &= 0xf; 293dd4493efSMauro Carvalho Chehab if (val >= 2) 294dd4493efSMauro Carvalho Chehab *status |= FE_HAS_SIGNAL; 2959a0bf528SMauro Carvalho Chehab 296dd4493efSMauro Carvalho Chehab if (val >= 4) 297dd4493efSMauro Carvalho Chehab *status |= FE_HAS_CARRIER; 2989a0bf528SMauro Carvalho Chehab 299dd4493efSMauro Carvalho Chehab if (val >= 5) 300dd4493efSMauro Carvalho Chehab *status |= FE_HAS_VITERBI; 3019a0bf528SMauro Carvalho Chehab 302dd4493efSMauro Carvalho Chehab if (val >= 7) 303dd4493efSMauro Carvalho Chehab *status |= FE_HAS_SYNC; 3049a0bf528SMauro Carvalho Chehab 305dafb65fbSMauro Carvalho Chehab /* 306dafb65fbSMauro Carvalho Chehab * Actually, on state S8, it starts receiving TS, but the TS 307dafb65fbSMauro Carvalho Chehab * output is only on normal state after the transition to S9. 308dafb65fbSMauro Carvalho Chehab */ 309dafb65fbSMauro Carvalho Chehab if (val >= 9) 310dd4493efSMauro Carvalho Chehab *status |= FE_HAS_LOCK; 311dd4493efSMauro Carvalho Chehab 312f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s: Status = 0x%02x (state = %d)\n", 313f66d81b5SMauro Carvalho Chehab __func__, *status, val); 314dd4493efSMauro Carvalho Chehab 31515b1c5a0SMauro Carvalho Chehab return val; 3169a0bf528SMauro Carvalho Chehab } 3179a0bf528SMauro Carvalho Chehab 31809b6d21eSMauro Carvalho Chehab static int mb86a20s_read_signal_strength(struct dvb_frontend *fe) 3199a0bf528SMauro Carvalho Chehab { 3209a0bf528SMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 3210921ecfdSMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 32209b6d21eSMauro Carvalho Chehab int rc; 3239a0bf528SMauro Carvalho Chehab unsigned rf_max, rf_min, rf; 3249a0bf528SMauro Carvalho Chehab 3250921ecfdSMauro Carvalho Chehab if (state->get_strength_time && 3260921ecfdSMauro Carvalho Chehab (!time_after(jiffies, state->get_strength_time))) 3270921ecfdSMauro Carvalho Chehab return c->strength.stat[0].uvalue; 3280921ecfdSMauro Carvalho Chehab 3290921ecfdSMauro Carvalho Chehab /* Reset its value if an error happen */ 3300921ecfdSMauro Carvalho Chehab c->strength.stat[0].uvalue = 0; 3310921ecfdSMauro Carvalho Chehab 3329a0bf528SMauro Carvalho Chehab /* Does a binary search to get RF strength */ 3339a0bf528SMauro Carvalho Chehab rf_max = 0xfff; 3349a0bf528SMauro Carvalho Chehab rf_min = 0; 3359a0bf528SMauro Carvalho Chehab do { 3369a0bf528SMauro Carvalho Chehab rf = (rf_max + rf_min) / 2; 33709b6d21eSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x04, 0x1f); 33809b6d21eSMauro Carvalho Chehab if (rc < 0) 33909b6d21eSMauro Carvalho Chehab return rc; 34009b6d21eSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x05, rf >> 8); 34109b6d21eSMauro Carvalho Chehab if (rc < 0) 34209b6d21eSMauro Carvalho Chehab return rc; 34309b6d21eSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x04, 0x20); 34409b6d21eSMauro Carvalho Chehab if (rc < 0) 34509b6d21eSMauro Carvalho Chehab return rc; 346dad78c56SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x05, rf); 34709b6d21eSMauro Carvalho Chehab if (rc < 0) 34809b6d21eSMauro Carvalho Chehab return rc; 3499a0bf528SMauro Carvalho Chehab 35009b6d21eSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x02); 35109b6d21eSMauro Carvalho Chehab if (rc < 0) 35209b6d21eSMauro Carvalho Chehab return rc; 35309b6d21eSMauro Carvalho Chehab if (rc & 0x08) 3549a0bf528SMauro Carvalho Chehab rf_min = (rf_max + rf_min) / 2; 3559a0bf528SMauro Carvalho Chehab else 3569a0bf528SMauro Carvalho Chehab rf_max = (rf_max + rf_min) / 2; 3579a0bf528SMauro Carvalho Chehab if (rf_max - rf_min < 4) { 35809b6d21eSMauro Carvalho Chehab rf = (rf_max + rf_min) / 2; 35909b6d21eSMauro Carvalho Chehab 36009b6d21eSMauro Carvalho Chehab /* Rescale it from 2^12 (4096) to 2^16 */ 3610921ecfdSMauro Carvalho Chehab rf = rf << (16 - 12); 3620921ecfdSMauro Carvalho Chehab if (rf) 3630921ecfdSMauro Carvalho Chehab rf |= (1 << 12) - 1; 3640921ecfdSMauro Carvalho Chehab 365f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 366f66d81b5SMauro Carvalho Chehab "%s: signal strength = %d (%d < RF=%d < %d)\n", 367f66d81b5SMauro Carvalho Chehab __func__, rf, rf_min, rf >> 4, rf_max); 3680921ecfdSMauro Carvalho Chehab c->strength.stat[0].uvalue = rf; 3690921ecfdSMauro Carvalho Chehab state->get_strength_time = jiffies + 3700921ecfdSMauro Carvalho Chehab msecs_to_jiffies(1000); 3710921ecfdSMauro Carvalho Chehab return 0; 3729a0bf528SMauro Carvalho Chehab } 3739a0bf528SMauro Carvalho Chehab } while (1); 3749a0bf528SMauro Carvalho Chehab } 3759a0bf528SMauro Carvalho Chehab 3769a0bf528SMauro Carvalho Chehab static int mb86a20s_get_modulation(struct mb86a20s_state *state, 3779a0bf528SMauro Carvalho Chehab unsigned layer) 3789a0bf528SMauro Carvalho Chehab { 3799a0bf528SMauro Carvalho Chehab int rc; 3809a0bf528SMauro Carvalho Chehab static unsigned char reg[] = { 3819a0bf528SMauro Carvalho Chehab [0] = 0x86, /* Layer A */ 3829a0bf528SMauro Carvalho Chehab [1] = 0x8a, /* Layer B */ 3839a0bf528SMauro Carvalho Chehab [2] = 0x8e, /* Layer C */ 3849a0bf528SMauro Carvalho Chehab }; 3859a0bf528SMauro Carvalho Chehab 3869a0bf528SMauro Carvalho Chehab if (layer >= ARRAY_SIZE(reg)) 3879a0bf528SMauro Carvalho Chehab return -EINVAL; 3889a0bf528SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x6d, reg[layer]); 3899a0bf528SMauro Carvalho Chehab if (rc < 0) 3909a0bf528SMauro Carvalho Chehab return rc; 3919a0bf528SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x6e); 3929a0bf528SMauro Carvalho Chehab if (rc < 0) 3939a0bf528SMauro Carvalho Chehab return rc; 39404585921SMauro Carvalho Chehab switch ((rc >> 4) & 0x07) { 3959a0bf528SMauro Carvalho Chehab case 0: 3969a0bf528SMauro Carvalho Chehab return DQPSK; 3979a0bf528SMauro Carvalho Chehab case 1: 3989a0bf528SMauro Carvalho Chehab return QPSK; 3999a0bf528SMauro Carvalho Chehab case 2: 4009a0bf528SMauro Carvalho Chehab return QAM_16; 4019a0bf528SMauro Carvalho Chehab case 3: 4029a0bf528SMauro Carvalho Chehab return QAM_64; 4039a0bf528SMauro Carvalho Chehab default: 4049a0bf528SMauro Carvalho Chehab return QAM_AUTO; 4059a0bf528SMauro Carvalho Chehab } 4069a0bf528SMauro Carvalho Chehab } 4079a0bf528SMauro Carvalho Chehab 4089a0bf528SMauro Carvalho Chehab static int mb86a20s_get_fec(struct mb86a20s_state *state, 4099a0bf528SMauro Carvalho Chehab unsigned layer) 4109a0bf528SMauro Carvalho Chehab { 4119a0bf528SMauro Carvalho Chehab int rc; 4129a0bf528SMauro Carvalho Chehab 4139a0bf528SMauro Carvalho Chehab static unsigned char reg[] = { 4149a0bf528SMauro Carvalho Chehab [0] = 0x87, /* Layer A */ 4159a0bf528SMauro Carvalho Chehab [1] = 0x8b, /* Layer B */ 4169a0bf528SMauro Carvalho Chehab [2] = 0x8f, /* Layer C */ 4179a0bf528SMauro Carvalho Chehab }; 4189a0bf528SMauro Carvalho Chehab 4199a0bf528SMauro Carvalho Chehab if (layer >= ARRAY_SIZE(reg)) 4209a0bf528SMauro Carvalho Chehab return -EINVAL; 4219a0bf528SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x6d, reg[layer]); 4229a0bf528SMauro Carvalho Chehab if (rc < 0) 4239a0bf528SMauro Carvalho Chehab return rc; 4249a0bf528SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x6e); 4259a0bf528SMauro Carvalho Chehab if (rc < 0) 4269a0bf528SMauro Carvalho Chehab return rc; 42704585921SMauro Carvalho Chehab switch ((rc >> 4) & 0x07) { 4289a0bf528SMauro Carvalho Chehab case 0: 4299a0bf528SMauro Carvalho Chehab return FEC_1_2; 4309a0bf528SMauro Carvalho Chehab case 1: 4319a0bf528SMauro Carvalho Chehab return FEC_2_3; 4329a0bf528SMauro Carvalho Chehab case 2: 4339a0bf528SMauro Carvalho Chehab return FEC_3_4; 4349a0bf528SMauro Carvalho Chehab case 3: 4359a0bf528SMauro Carvalho Chehab return FEC_5_6; 4369a0bf528SMauro Carvalho Chehab case 4: 4379a0bf528SMauro Carvalho Chehab return FEC_7_8; 4389a0bf528SMauro Carvalho Chehab default: 4399a0bf528SMauro Carvalho Chehab return FEC_AUTO; 4409a0bf528SMauro Carvalho Chehab } 4419a0bf528SMauro Carvalho Chehab } 4429a0bf528SMauro Carvalho Chehab 4439a0bf528SMauro Carvalho Chehab static int mb86a20s_get_interleaving(struct mb86a20s_state *state, 4449a0bf528SMauro Carvalho Chehab unsigned layer) 4459a0bf528SMauro Carvalho Chehab { 4469a0bf528SMauro Carvalho Chehab int rc; 44757b660b2SColin Ian King static const int interleaving[] = { 4484247368bSMauro Carvalho Chehab 0, 1, 2, 4, 8 4494247368bSMauro Carvalho Chehab }; 4509a0bf528SMauro Carvalho Chehab 45157b660b2SColin Ian King static const unsigned char reg[] = { 4529a0bf528SMauro Carvalho Chehab [0] = 0x88, /* Layer A */ 4539a0bf528SMauro Carvalho Chehab [1] = 0x8c, /* Layer B */ 4549a0bf528SMauro Carvalho Chehab [2] = 0x90, /* Layer C */ 4559a0bf528SMauro Carvalho Chehab }; 4569a0bf528SMauro Carvalho Chehab 4579a0bf528SMauro Carvalho Chehab if (layer >= ARRAY_SIZE(reg)) 4589a0bf528SMauro Carvalho Chehab return -EINVAL; 4599a0bf528SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x6d, reg[layer]); 4609a0bf528SMauro Carvalho Chehab if (rc < 0) 4619a0bf528SMauro Carvalho Chehab return rc; 4629a0bf528SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x6e); 4639a0bf528SMauro Carvalho Chehab if (rc < 0) 4649a0bf528SMauro Carvalho Chehab return rc; 46504585921SMauro Carvalho Chehab 4664247368bSMauro Carvalho Chehab return interleaving[(rc >> 4) & 0x07]; 4679a0bf528SMauro Carvalho Chehab } 4689a0bf528SMauro Carvalho Chehab 4699a0bf528SMauro Carvalho Chehab static int mb86a20s_get_segment_count(struct mb86a20s_state *state, 4709a0bf528SMauro Carvalho Chehab unsigned layer) 4719a0bf528SMauro Carvalho Chehab { 4729a0bf528SMauro Carvalho Chehab int rc, count; 4739a0bf528SMauro Carvalho Chehab static unsigned char reg[] = { 4749a0bf528SMauro Carvalho Chehab [0] = 0x89, /* Layer A */ 4759a0bf528SMauro Carvalho Chehab [1] = 0x8d, /* Layer B */ 4769a0bf528SMauro Carvalho Chehab [2] = 0x91, /* Layer C */ 4779a0bf528SMauro Carvalho Chehab }; 4789a0bf528SMauro Carvalho Chehab 479f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 480f66d81b5SMauro Carvalho Chehab 4819a0bf528SMauro Carvalho Chehab if (layer >= ARRAY_SIZE(reg)) 4829a0bf528SMauro Carvalho Chehab return -EINVAL; 483f66d81b5SMauro Carvalho Chehab 4849a0bf528SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x6d, reg[layer]); 4859a0bf528SMauro Carvalho Chehab if (rc < 0) 4869a0bf528SMauro Carvalho Chehab return rc; 4879a0bf528SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x6e); 4889a0bf528SMauro Carvalho Chehab if (rc < 0) 4899a0bf528SMauro Carvalho Chehab return rc; 4909a0bf528SMauro Carvalho Chehab count = (rc >> 4) & 0x0f; 4919a0bf528SMauro Carvalho Chehab 492f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s: segments: %d.\n", __func__, count); 493f66d81b5SMauro Carvalho Chehab 4949a0bf528SMauro Carvalho Chehab return count; 4959a0bf528SMauro Carvalho Chehab } 4969a0bf528SMauro Carvalho Chehab 497a77cfcacSMauro Carvalho Chehab static void mb86a20s_reset_frontend_cache(struct dvb_frontend *fe) 498a77cfcacSMauro Carvalho Chehab { 499f66d81b5SMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 500a77cfcacSMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 501a77cfcacSMauro Carvalho Chehab 502f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 503f66d81b5SMauro Carvalho Chehab 504a77cfcacSMauro Carvalho Chehab /* Fixed parameters */ 505a77cfcacSMauro Carvalho Chehab c->delivery_system = SYS_ISDBT; 506a77cfcacSMauro Carvalho Chehab c->bandwidth_hz = 6000000; 507a77cfcacSMauro Carvalho Chehab 508a77cfcacSMauro Carvalho Chehab /* Initialize values that will be later autodetected */ 509a77cfcacSMauro Carvalho Chehab c->isdbt_layer_enabled = 0; 510a77cfcacSMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_AUTO; 511a77cfcacSMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_AUTO; 512a77cfcacSMauro Carvalho Chehab c->isdbt_sb_mode = 0; 513a77cfcacSMauro Carvalho Chehab c->isdbt_sb_segment_count = 0; 514a77cfcacSMauro Carvalho Chehab } 515a77cfcacSMauro Carvalho Chehab 516d01a8ee3SMauro Carvalho Chehab /* 517d01a8ee3SMauro Carvalho Chehab * Estimates the bit rate using the per-segment bit rate given by 518d01a8ee3SMauro Carvalho Chehab * ABNT/NBR 15601 spec (table 4). 519d01a8ee3SMauro Carvalho Chehab */ 52075564e3aSMauro Carvalho Chehab static const u32 isdbt_rate[3][5][4] = { 521d01a8ee3SMauro Carvalho Chehab { /* DQPSK/QPSK */ 522d01a8ee3SMauro Carvalho Chehab { 280850, 312060, 330420, 340430 }, /* 1/2 */ 523d01a8ee3SMauro Carvalho Chehab { 374470, 416080, 440560, 453910 }, /* 2/3 */ 524d01a8ee3SMauro Carvalho Chehab { 421280, 468090, 495630, 510650 }, /* 3/4 */ 525d01a8ee3SMauro Carvalho Chehab { 468090, 520100, 550700, 567390 }, /* 5/6 */ 526d01a8ee3SMauro Carvalho Chehab { 491500, 546110, 578230, 595760 }, /* 7/8 */ 527d01a8ee3SMauro Carvalho Chehab }, { /* QAM16 */ 528d01a8ee3SMauro Carvalho Chehab { 561710, 624130, 660840, 680870 }, /* 1/2 */ 529d01a8ee3SMauro Carvalho Chehab { 748950, 832170, 881120, 907820 }, /* 2/3 */ 530d01a8ee3SMauro Carvalho Chehab { 842570, 936190, 991260, 1021300 }, /* 3/4 */ 531d01a8ee3SMauro Carvalho Chehab { 936190, 1040210, 1101400, 1134780 }, /* 5/6 */ 532d01a8ee3SMauro Carvalho Chehab { 983000, 1092220, 1156470, 1191520 }, /* 7/8 */ 533d01a8ee3SMauro Carvalho Chehab }, { /* QAM64 */ 534d01a8ee3SMauro Carvalho Chehab { 842570, 936190, 991260, 1021300 }, /* 1/2 */ 535d01a8ee3SMauro Carvalho Chehab { 1123430, 1248260, 1321680, 1361740 }, /* 2/3 */ 536d01a8ee3SMauro Carvalho Chehab { 1263860, 1404290, 1486900, 1531950 }, /* 3/4 */ 537d01a8ee3SMauro Carvalho Chehab { 1404290, 1560320, 1652110, 1702170 }, /* 5/6 */ 538d01a8ee3SMauro Carvalho Chehab { 1474500, 1638340, 1734710, 1787280 }, /* 7/8 */ 539d01a8ee3SMauro Carvalho Chehab } 540d01a8ee3SMauro Carvalho Chehab }; 541d01a8ee3SMauro Carvalho Chehab 54275564e3aSMauro Carvalho Chehab static u32 isdbt_layer_min_bitrate(struct dtv_frontend_properties *c, 54375564e3aSMauro Carvalho Chehab u32 layer) 544d01a8ee3SMauro Carvalho Chehab { 5450562aef2SMauro Carvalho Chehab int mod, fec, guard; 546d01a8ee3SMauro Carvalho Chehab 547d01a8ee3SMauro Carvalho Chehab /* 548277bfd2fSMauro Carvalho Chehab * If modulation/fec/guard is not detected, the default is 549d01a8ee3SMauro Carvalho Chehab * to consider the lowest bit rate, to avoid taking too long time 550d01a8ee3SMauro Carvalho Chehab * to get BER. 551d01a8ee3SMauro Carvalho Chehab */ 55275564e3aSMauro Carvalho Chehab switch (c->layer[layer].modulation) { 553d01a8ee3SMauro Carvalho Chehab case DQPSK: 554d01a8ee3SMauro Carvalho Chehab case QPSK: 555d01a8ee3SMauro Carvalho Chehab default: 5560562aef2SMauro Carvalho Chehab mod = 0; 557d01a8ee3SMauro Carvalho Chehab break; 558d01a8ee3SMauro Carvalho Chehab case QAM_16: 5590562aef2SMauro Carvalho Chehab mod = 1; 560d01a8ee3SMauro Carvalho Chehab break; 561d01a8ee3SMauro Carvalho Chehab case QAM_64: 5620562aef2SMauro Carvalho Chehab mod = 2; 563d01a8ee3SMauro Carvalho Chehab break; 564d01a8ee3SMauro Carvalho Chehab } 565d01a8ee3SMauro Carvalho Chehab 56675564e3aSMauro Carvalho Chehab switch (c->layer[layer].fec) { 567d01a8ee3SMauro Carvalho Chehab default: 568d01a8ee3SMauro Carvalho Chehab case FEC_1_2: 569d01a8ee3SMauro Carvalho Chehab case FEC_AUTO: 5700562aef2SMauro Carvalho Chehab fec = 0; 571d01a8ee3SMauro Carvalho Chehab break; 572d01a8ee3SMauro Carvalho Chehab case FEC_2_3: 5730562aef2SMauro Carvalho Chehab fec = 1; 574d01a8ee3SMauro Carvalho Chehab break; 575d01a8ee3SMauro Carvalho Chehab case FEC_3_4: 5760562aef2SMauro Carvalho Chehab fec = 2; 577d01a8ee3SMauro Carvalho Chehab break; 578d01a8ee3SMauro Carvalho Chehab case FEC_5_6: 5790562aef2SMauro Carvalho Chehab fec = 3; 580d01a8ee3SMauro Carvalho Chehab break; 581d01a8ee3SMauro Carvalho Chehab case FEC_7_8: 5820562aef2SMauro Carvalho Chehab fec = 4; 583d01a8ee3SMauro Carvalho Chehab break; 584d01a8ee3SMauro Carvalho Chehab } 585d01a8ee3SMauro Carvalho Chehab 58675564e3aSMauro Carvalho Chehab switch (c->guard_interval) { 587d01a8ee3SMauro Carvalho Chehab default: 588d01a8ee3SMauro Carvalho Chehab case GUARD_INTERVAL_1_4: 5890562aef2SMauro Carvalho Chehab guard = 0; 590d01a8ee3SMauro Carvalho Chehab break; 591d01a8ee3SMauro Carvalho Chehab case GUARD_INTERVAL_1_8: 5920562aef2SMauro Carvalho Chehab guard = 1; 593d01a8ee3SMauro Carvalho Chehab break; 594d01a8ee3SMauro Carvalho Chehab case GUARD_INTERVAL_1_16: 5950562aef2SMauro Carvalho Chehab guard = 2; 596d01a8ee3SMauro Carvalho Chehab break; 597d01a8ee3SMauro Carvalho Chehab case GUARD_INTERVAL_1_32: 5980562aef2SMauro Carvalho Chehab guard = 3; 599d01a8ee3SMauro Carvalho Chehab break; 600d01a8ee3SMauro Carvalho Chehab } 601d01a8ee3SMauro Carvalho Chehab 60275564e3aSMauro Carvalho Chehab return isdbt_rate[mod][fec][guard] * c->layer[layer].segment_count; 603d01a8ee3SMauro Carvalho Chehab } 604d01a8ee3SMauro Carvalho Chehab 6059a0bf528SMauro Carvalho Chehab static int mb86a20s_get_frontend(struct dvb_frontend *fe) 6069a0bf528SMauro Carvalho Chehab { 6079a0bf528SMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 608a77cfcacSMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 60975564e3aSMauro Carvalho Chehab int layer, rc, rate, counter; 6109a0bf528SMauro Carvalho Chehab 611f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 612f66d81b5SMauro Carvalho Chehab 613a77cfcacSMauro Carvalho Chehab /* Reset frontend cache to default values */ 614a77cfcacSMauro Carvalho Chehab mb86a20s_reset_frontend_cache(fe); 6159a0bf528SMauro Carvalho Chehab 6169a0bf528SMauro Carvalho Chehab /* Check for partial reception */ 6179a0bf528SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x6d, 0x85); 618a77cfcacSMauro Carvalho Chehab if (rc < 0) 619a77cfcacSMauro Carvalho Chehab return rc; 6209a0bf528SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x6e); 621a77cfcacSMauro Carvalho Chehab if (rc < 0) 622a77cfcacSMauro Carvalho Chehab return rc; 623a77cfcacSMauro Carvalho Chehab c->isdbt_partial_reception = (rc & 0x10) ? 1 : 0; 6249a0bf528SMauro Carvalho Chehab 6259a0bf528SMauro Carvalho Chehab /* Get per-layer data */ 626a77cfcacSMauro Carvalho Chehab 6275cb88ca8SMauro Carvalho Chehab for (layer = 0; layer < NUM_LAYERS; layer++) { 628f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s: getting data for layer %c.\n", 6295cb88ca8SMauro Carvalho Chehab __func__, 'A' + layer); 630f66d81b5SMauro Carvalho Chehab 6315cb88ca8SMauro Carvalho Chehab rc = mb86a20s_get_segment_count(state, layer); 632a77cfcacSMauro Carvalho Chehab if (rc < 0) 633f66d81b5SMauro Carvalho Chehab goto noperlayer_error; 634d01a8ee3SMauro Carvalho Chehab if (rc >= 0 && rc < 14) { 6355cb88ca8SMauro Carvalho Chehab c->layer[layer].segment_count = rc; 636d01a8ee3SMauro Carvalho Chehab } else { 6375cb88ca8SMauro Carvalho Chehab c->layer[layer].segment_count = 0; 6385cb88ca8SMauro Carvalho Chehab state->estimated_rate[layer] = 0; 6399a0bf528SMauro Carvalho Chehab continue; 640a77cfcacSMauro Carvalho Chehab } 6415cb88ca8SMauro Carvalho Chehab c->isdbt_layer_enabled |= 1 << layer; 6425cb88ca8SMauro Carvalho Chehab rc = mb86a20s_get_modulation(state, layer); 643a77cfcacSMauro Carvalho Chehab if (rc < 0) 644f66d81b5SMauro Carvalho Chehab goto noperlayer_error; 645f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s: modulation %d.\n", 646f66d81b5SMauro Carvalho Chehab __func__, rc); 6475cb88ca8SMauro Carvalho Chehab c->layer[layer].modulation = rc; 6485cb88ca8SMauro Carvalho Chehab rc = mb86a20s_get_fec(state, layer); 649a77cfcacSMauro Carvalho Chehab if (rc < 0) 650f66d81b5SMauro Carvalho Chehab goto noperlayer_error; 651f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s: FEC %d.\n", 652f66d81b5SMauro Carvalho Chehab __func__, rc); 6535cb88ca8SMauro Carvalho Chehab c->layer[layer].fec = rc; 6545cb88ca8SMauro Carvalho Chehab rc = mb86a20s_get_interleaving(state, layer); 655a77cfcacSMauro Carvalho Chehab if (rc < 0) 656f66d81b5SMauro Carvalho Chehab goto noperlayer_error; 657f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s: interleaving %d.\n", 658f66d81b5SMauro Carvalho Chehab __func__, rc); 6595cb88ca8SMauro Carvalho Chehab c->layer[layer].interleaving = rc; 66075564e3aSMauro Carvalho Chehab 66175564e3aSMauro Carvalho Chehab rate = isdbt_layer_min_bitrate(c, layer); 66275564e3aSMauro Carvalho Chehab counter = rate * BER_SAMPLING_RATE; 66375564e3aSMauro Carvalho Chehab 66475564e3aSMauro Carvalho Chehab /* Avoids sampling too quickly or to overflow the register */ 66575564e3aSMauro Carvalho Chehab if (counter < 256) 66675564e3aSMauro Carvalho Chehab counter = 256; 66775564e3aSMauro Carvalho Chehab else if (counter > (1 << 24) - 1) 66875564e3aSMauro Carvalho Chehab counter = (1 << 24) - 1; 66975564e3aSMauro Carvalho Chehab 67075564e3aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 67175564e3aSMauro Carvalho Chehab "%s: layer %c bitrate: %d kbps; counter = %d (0x%06x)\n", 67275564e3aSMauro Carvalho Chehab __func__, 'A' + layer, rate / 1000, counter, counter); 67375564e3aSMauro Carvalho Chehab 67475564e3aSMauro Carvalho Chehab state->estimated_rate[layer] = counter; 6759a0bf528SMauro Carvalho Chehab } 6769a0bf528SMauro Carvalho Chehab 6779a0bf528SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x6d, 0x84); 678a77cfcacSMauro Carvalho Chehab if (rc < 0) 679a77cfcacSMauro Carvalho Chehab return rc; 680a77cfcacSMauro Carvalho Chehab if ((rc & 0x60) == 0x20) { 681a77cfcacSMauro Carvalho Chehab c->isdbt_sb_mode = 1; 6829a0bf528SMauro Carvalho Chehab /* At least, one segment should exist */ 683a77cfcacSMauro Carvalho Chehab if (!c->isdbt_sb_segment_count) 684a77cfcacSMauro Carvalho Chehab c->isdbt_sb_segment_count = 1; 685a77cfcacSMauro Carvalho Chehab } 6869a0bf528SMauro Carvalho Chehab 6879a0bf528SMauro Carvalho Chehab /* Get transmission mode and guard interval */ 6889a0bf528SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x07); 689a77cfcacSMauro Carvalho Chehab if (rc < 0) 690a77cfcacSMauro Carvalho Chehab return rc; 691276dfc4bSMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_AUTO; 6929a0bf528SMauro Carvalho Chehab if ((rc & 0x60) == 0x20) { 693276dfc4bSMauro Carvalho Chehab /* Only modes 2 and 3 are supported */ 694276dfc4bSMauro Carvalho Chehab switch ((rc >> 2) & 0x03) { 6959a0bf528SMauro Carvalho Chehab case 1: 696a77cfcacSMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_4K; 6979a0bf528SMauro Carvalho Chehab break; 6989a0bf528SMauro Carvalho Chehab case 2: 699a77cfcacSMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K; 7009a0bf528SMauro Carvalho Chehab break; 7019a0bf528SMauro Carvalho Chehab } 7029a0bf528SMauro Carvalho Chehab } 703276dfc4bSMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_AUTO; 7049a0bf528SMauro Carvalho Chehab if (!(rc & 0x10)) { 705276dfc4bSMauro Carvalho Chehab /* Guard interval 1/32 is not supported */ 7069a0bf528SMauro Carvalho Chehab switch (rc & 0x3) { 7079a0bf528SMauro Carvalho Chehab case 0: 708a77cfcacSMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_4; 7099a0bf528SMauro Carvalho Chehab break; 7109a0bf528SMauro Carvalho Chehab case 1: 711a77cfcacSMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8; 7129a0bf528SMauro Carvalho Chehab break; 7139a0bf528SMauro Carvalho Chehab case 2: 714a77cfcacSMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_16; 7159a0bf528SMauro Carvalho Chehab break; 7169a0bf528SMauro Carvalho Chehab } 7179a0bf528SMauro Carvalho Chehab } 71809b6d21eSMauro Carvalho Chehab return 0; 7199a0bf528SMauro Carvalho Chehab 720f66d81b5SMauro Carvalho Chehab noperlayer_error: 72109b6d21eSMauro Carvalho Chehab 72209b6d21eSMauro Carvalho Chehab /* per-layer info is incomplete; discard all per-layer */ 72309b6d21eSMauro Carvalho Chehab c->isdbt_layer_enabled = 0; 7249a0bf528SMauro Carvalho Chehab 725a77cfcacSMauro Carvalho Chehab return rc; 7269a0bf528SMauro Carvalho Chehab } 7279a0bf528SMauro Carvalho Chehab 72809b6d21eSMauro Carvalho Chehab static int mb86a20s_reset_counters(struct dvb_frontend *fe) 72909b6d21eSMauro Carvalho Chehab { 73009b6d21eSMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 73109b6d21eSMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 73209b6d21eSMauro Carvalho Chehab int rc, val; 73309b6d21eSMauro Carvalho Chehab 73409b6d21eSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 73509b6d21eSMauro Carvalho Chehab 73609b6d21eSMauro Carvalho Chehab /* Reset the counters, if the channel changed */ 73709b6d21eSMauro Carvalho Chehab if (state->last_frequency != c->frequency) { 73809b6d21eSMauro Carvalho Chehab memset(&c->cnr, 0, sizeof(c->cnr)); 73909b6d21eSMauro Carvalho Chehab memset(&c->pre_bit_error, 0, sizeof(c->pre_bit_error)); 74009b6d21eSMauro Carvalho Chehab memset(&c->pre_bit_count, 0, sizeof(c->pre_bit_count)); 741d9b6f08aSMauro Carvalho Chehab memset(&c->post_bit_error, 0, sizeof(c->post_bit_error)); 742d9b6f08aSMauro Carvalho Chehab memset(&c->post_bit_count, 0, sizeof(c->post_bit_count)); 74309b6d21eSMauro Carvalho Chehab memset(&c->block_error, 0, sizeof(c->block_error)); 74409b6d21eSMauro Carvalho Chehab memset(&c->block_count, 0, sizeof(c->block_count)); 74509b6d21eSMauro Carvalho Chehab 74609b6d21eSMauro Carvalho Chehab state->last_frequency = c->frequency; 74709b6d21eSMauro Carvalho Chehab } 74809b6d21eSMauro Carvalho Chehab 74909b6d21eSMauro Carvalho Chehab /* Clear status for most stats */ 75009b6d21eSMauro Carvalho Chehab 751d9b6f08aSMauro Carvalho Chehab /* BER/PER counter reset */ 752d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_writeregdata(state, mb86a20s_per_ber_reset); 75309b6d21eSMauro Carvalho Chehab if (rc < 0) 75409b6d21eSMauro Carvalho Chehab goto err; 75509b6d21eSMauro Carvalho Chehab 75609b6d21eSMauro Carvalho Chehab /* CNR counter reset */ 75709b6d21eSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x45); 75809b6d21eSMauro Carvalho Chehab if (rc < 0) 75909b6d21eSMauro Carvalho Chehab goto err; 76009b6d21eSMauro Carvalho Chehab val = rc; 76109b6d21eSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x45, val | 0x10); 76209b6d21eSMauro Carvalho Chehab if (rc < 0) 76309b6d21eSMauro Carvalho Chehab goto err; 76409b6d21eSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x45, val & 0x6f); 76509b6d21eSMauro Carvalho Chehab if (rc < 0) 76609b6d21eSMauro Carvalho Chehab goto err; 76709b6d21eSMauro Carvalho Chehab 76809b6d21eSMauro Carvalho Chehab /* MER counter reset */ 76909b6d21eSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0x50); 77009b6d21eSMauro Carvalho Chehab if (rc < 0) 77109b6d21eSMauro Carvalho Chehab goto err; 77209b6d21eSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 77309b6d21eSMauro Carvalho Chehab if (rc < 0) 77409b6d21eSMauro Carvalho Chehab goto err; 77509b6d21eSMauro Carvalho Chehab val = rc; 77609b6d21eSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, val | 0x01); 77709b6d21eSMauro Carvalho Chehab if (rc < 0) 77809b6d21eSMauro Carvalho Chehab goto err; 77909b6d21eSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, val & 0x06); 78009b6d21eSMauro Carvalho Chehab if (rc < 0) 78109b6d21eSMauro Carvalho Chehab goto err; 78209b6d21eSMauro Carvalho Chehab 783149d518aSMauro Carvalho Chehab goto ok; 78409b6d21eSMauro Carvalho Chehab err: 785149d518aSMauro Carvalho Chehab dev_err(&state->i2c->dev, 786149d518aSMauro Carvalho Chehab "%s: Can't reset FE statistics (error %d).\n", 787149d518aSMauro Carvalho Chehab __func__, rc); 788149d518aSMauro Carvalho Chehab ok: 78909b6d21eSMauro Carvalho Chehab return rc; 79009b6d21eSMauro Carvalho Chehab } 79109b6d21eSMauro Carvalho Chehab 792ad0abbf1SMauro Carvalho Chehab static int mb86a20s_get_pre_ber(struct dvb_frontend *fe, 793149d518aSMauro Carvalho Chehab unsigned layer, 794149d518aSMauro Carvalho Chehab u32 *error, u32 *count) 795149d518aSMauro Carvalho Chehab { 796149d518aSMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 797ad0abbf1SMauro Carvalho Chehab int rc, val; 798149d518aSMauro Carvalho Chehab 799149d518aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 800149d518aSMauro Carvalho Chehab 8014f62a20dSMauro Carvalho Chehab if (layer >= NUM_LAYERS) 802149d518aSMauro Carvalho Chehab return -EINVAL; 803149d518aSMauro Carvalho Chehab 804149d518aSMauro Carvalho Chehab /* Check if the BER measures are already available */ 805149d518aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x54); 806149d518aSMauro Carvalho Chehab if (rc < 0) 807149d518aSMauro Carvalho Chehab return rc; 808149d518aSMauro Carvalho Chehab 809149d518aSMauro Carvalho Chehab /* Check if data is available for that layer */ 810149d518aSMauro Carvalho Chehab if (!(rc & (1 << layer))) { 811149d518aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 812ad0abbf1SMauro Carvalho Chehab "%s: preBER for layer %c is not available yet.\n", 813149d518aSMauro Carvalho Chehab __func__, 'A' + layer); 814149d518aSMauro Carvalho Chehab return -EBUSY; 815149d518aSMauro Carvalho Chehab } 816149d518aSMauro Carvalho Chehab 817149d518aSMauro Carvalho Chehab /* Read Bit Error Count */ 818149d518aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x55 + layer * 3); 819149d518aSMauro Carvalho Chehab if (rc < 0) 820149d518aSMauro Carvalho Chehab return rc; 821149d518aSMauro Carvalho Chehab *error = rc << 16; 822149d518aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x56 + layer * 3); 823149d518aSMauro Carvalho Chehab if (rc < 0) 824149d518aSMauro Carvalho Chehab return rc; 825149d518aSMauro Carvalho Chehab *error |= rc << 8; 826149d518aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x57 + layer * 3); 827149d518aSMauro Carvalho Chehab if (rc < 0) 828149d518aSMauro Carvalho Chehab return rc; 829149d518aSMauro Carvalho Chehab *error |= rc; 830149d518aSMauro Carvalho Chehab 831149d518aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 832149d518aSMauro Carvalho Chehab "%s: bit error before Viterbi for layer %c: %d.\n", 833149d518aSMauro Carvalho Chehab __func__, 'A' + layer, *error); 834149d518aSMauro Carvalho Chehab 835149d518aSMauro Carvalho Chehab /* Read Bit Count */ 836149d518aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xa7 + layer * 3); 837149d518aSMauro Carvalho Chehab if (rc < 0) 838149d518aSMauro Carvalho Chehab return rc; 839149d518aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 840149d518aSMauro Carvalho Chehab if (rc < 0) 841149d518aSMauro Carvalho Chehab return rc; 842149d518aSMauro Carvalho Chehab *count = rc << 16; 843149d518aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xa8 + layer * 3); 844149d518aSMauro Carvalho Chehab if (rc < 0) 845149d518aSMauro Carvalho Chehab return rc; 846149d518aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 847149d518aSMauro Carvalho Chehab if (rc < 0) 848149d518aSMauro Carvalho Chehab return rc; 849149d518aSMauro Carvalho Chehab *count |= rc << 8; 850149d518aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xa9 + layer * 3); 851149d518aSMauro Carvalho Chehab if (rc < 0) 852149d518aSMauro Carvalho Chehab return rc; 853149d518aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 854149d518aSMauro Carvalho Chehab if (rc < 0) 855149d518aSMauro Carvalho Chehab return rc; 856149d518aSMauro Carvalho Chehab *count |= rc; 857149d518aSMauro Carvalho Chehab 858149d518aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 859149d518aSMauro Carvalho Chehab "%s: bit count before Viterbi for layer %c: %d.\n", 860149d518aSMauro Carvalho Chehab __func__, 'A' + layer, *count); 861149d518aSMauro Carvalho Chehab 862149d518aSMauro Carvalho Chehab 863d01a8ee3SMauro Carvalho Chehab /* 864d01a8ee3SMauro Carvalho Chehab * As we get TMCC data from the frontend, we can better estimate the 865d01a8ee3SMauro Carvalho Chehab * BER bit counters, in order to do the BER measure during a longer 866d01a8ee3SMauro Carvalho Chehab * time. Use those data, if available, to update the bit count 867d01a8ee3SMauro Carvalho Chehab * measure. 868d01a8ee3SMauro Carvalho Chehab */ 869d01a8ee3SMauro Carvalho Chehab 870d01a8ee3SMauro Carvalho Chehab if (state->estimated_rate[layer] 871d01a8ee3SMauro Carvalho Chehab && state->estimated_rate[layer] != *count) { 872d01a8ee3SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 873ad0abbf1SMauro Carvalho Chehab "%s: updating layer %c preBER counter to %d.\n", 874d01a8ee3SMauro Carvalho Chehab __func__, 'A' + layer, state->estimated_rate[layer]); 875ad0abbf1SMauro Carvalho Chehab 876ad0abbf1SMauro Carvalho Chehab /* Turn off BER before Viterbi */ 877ad0abbf1SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x52, 0x00); 878ad0abbf1SMauro Carvalho Chehab 879ad0abbf1SMauro Carvalho Chehab /* Update counter for this layer */ 880d01a8ee3SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xa7 + layer * 3); 881d01a8ee3SMauro Carvalho Chehab if (rc < 0) 882d01a8ee3SMauro Carvalho Chehab return rc; 883d01a8ee3SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, 884d01a8ee3SMauro Carvalho Chehab state->estimated_rate[layer] >> 16); 885d01a8ee3SMauro Carvalho Chehab if (rc < 0) 886d01a8ee3SMauro Carvalho Chehab return rc; 887d01a8ee3SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xa8 + layer * 3); 888d01a8ee3SMauro Carvalho Chehab if (rc < 0) 889d01a8ee3SMauro Carvalho Chehab return rc; 890d01a8ee3SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, 891d01a8ee3SMauro Carvalho Chehab state->estimated_rate[layer] >> 8); 892d01a8ee3SMauro Carvalho Chehab if (rc < 0) 893d01a8ee3SMauro Carvalho Chehab return rc; 894d01a8ee3SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xa9 + layer * 3); 895d01a8ee3SMauro Carvalho Chehab if (rc < 0) 896d01a8ee3SMauro Carvalho Chehab return rc; 897d01a8ee3SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, 898d01a8ee3SMauro Carvalho Chehab state->estimated_rate[layer]); 899d01a8ee3SMauro Carvalho Chehab if (rc < 0) 900d01a8ee3SMauro Carvalho Chehab return rc; 901ad0abbf1SMauro Carvalho Chehab 902ad0abbf1SMauro Carvalho Chehab /* Turn on BER before Viterbi */ 903ad0abbf1SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x52, 0x01); 904ad0abbf1SMauro Carvalho Chehab 905ad0abbf1SMauro Carvalho Chehab /* Reset all preBER counters */ 906ad0abbf1SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x53, 0x00); 907ad0abbf1SMauro Carvalho Chehab if (rc < 0) 908ad0abbf1SMauro Carvalho Chehab return rc; 909ad0abbf1SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x53, 0x07); 910ad0abbf1SMauro Carvalho Chehab } else { 911ad0abbf1SMauro Carvalho Chehab /* Reset counter to collect new data */ 912ad0abbf1SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x53); 913ad0abbf1SMauro Carvalho Chehab if (rc < 0) 914ad0abbf1SMauro Carvalho Chehab return rc; 915ad0abbf1SMauro Carvalho Chehab val = rc; 916ad0abbf1SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x53, val & ~(1 << layer)); 917ad0abbf1SMauro Carvalho Chehab if (rc < 0) 918ad0abbf1SMauro Carvalho Chehab return rc; 919ad0abbf1SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x53, val | (1 << layer)); 920d01a8ee3SMauro Carvalho Chehab } 921d01a8ee3SMauro Carvalho Chehab 922d9b6f08aSMauro Carvalho Chehab return rc; 923d9b6f08aSMauro Carvalho Chehab } 924d01a8ee3SMauro Carvalho Chehab 925d9b6f08aSMauro Carvalho Chehab static int mb86a20s_get_post_ber(struct dvb_frontend *fe, 926d9b6f08aSMauro Carvalho Chehab unsigned layer, 927d9b6f08aSMauro Carvalho Chehab u32 *error, u32 *count) 928d9b6f08aSMauro Carvalho Chehab { 929d9b6f08aSMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 930d9b6f08aSMauro Carvalho Chehab u32 counter, collect_rate; 931d9b6f08aSMauro Carvalho Chehab int rc, val; 932d9b6f08aSMauro Carvalho Chehab 933d9b6f08aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 934d9b6f08aSMauro Carvalho Chehab 9354f62a20dSMauro Carvalho Chehab if (layer >= NUM_LAYERS) 936d9b6f08aSMauro Carvalho Chehab return -EINVAL; 937d9b6f08aSMauro Carvalho Chehab 938d9b6f08aSMauro Carvalho Chehab /* Check if the BER measures are already available */ 939d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x60); 940d9b6f08aSMauro Carvalho Chehab if (rc < 0) 941d9b6f08aSMauro Carvalho Chehab return rc; 942d9b6f08aSMauro Carvalho Chehab 943d9b6f08aSMauro Carvalho Chehab /* Check if data is available for that layer */ 944d9b6f08aSMauro Carvalho Chehab if (!(rc & (1 << layer))) { 945d9b6f08aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 946d9b6f08aSMauro Carvalho Chehab "%s: post BER for layer %c is not available yet.\n", 947d9b6f08aSMauro Carvalho Chehab __func__, 'A' + layer); 948d9b6f08aSMauro Carvalho Chehab return -EBUSY; 949d9b6f08aSMauro Carvalho Chehab } 950d9b6f08aSMauro Carvalho Chehab 951d9b6f08aSMauro Carvalho Chehab /* Read Bit Error Count */ 952d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x64 + layer * 3); 953d9b6f08aSMauro Carvalho Chehab if (rc < 0) 954d9b6f08aSMauro Carvalho Chehab return rc; 955d9b6f08aSMauro Carvalho Chehab *error = rc << 16; 956d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x65 + layer * 3); 957d9b6f08aSMauro Carvalho Chehab if (rc < 0) 958d9b6f08aSMauro Carvalho Chehab return rc; 959d9b6f08aSMauro Carvalho Chehab *error |= rc << 8; 960d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x66 + layer * 3); 961d9b6f08aSMauro Carvalho Chehab if (rc < 0) 962d9b6f08aSMauro Carvalho Chehab return rc; 963d9b6f08aSMauro Carvalho Chehab *error |= rc; 964d9b6f08aSMauro Carvalho Chehab 965d9b6f08aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 966d9b6f08aSMauro Carvalho Chehab "%s: post bit error for layer %c: %d.\n", 967d9b6f08aSMauro Carvalho Chehab __func__, 'A' + layer, *error); 968d9b6f08aSMauro Carvalho Chehab 969d9b6f08aSMauro Carvalho Chehab /* Read Bit Count */ 970d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xdc + layer * 2); 971d9b6f08aSMauro Carvalho Chehab if (rc < 0) 972d9b6f08aSMauro Carvalho Chehab return rc; 973d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 974d9b6f08aSMauro Carvalho Chehab if (rc < 0) 975d9b6f08aSMauro Carvalho Chehab return rc; 976d9b6f08aSMauro Carvalho Chehab counter = rc << 8; 977d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xdd + layer * 2); 978d9b6f08aSMauro Carvalho Chehab if (rc < 0) 979d9b6f08aSMauro Carvalho Chehab return rc; 980d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 981d9b6f08aSMauro Carvalho Chehab if (rc < 0) 982d9b6f08aSMauro Carvalho Chehab return rc; 983d9b6f08aSMauro Carvalho Chehab counter |= rc; 984d9b6f08aSMauro Carvalho Chehab *count = counter * 204 * 8; 985d9b6f08aSMauro Carvalho Chehab 986d9b6f08aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 987d9b6f08aSMauro Carvalho Chehab "%s: post bit count for layer %c: %d.\n", 988d9b6f08aSMauro Carvalho Chehab __func__, 'A' + layer, *count); 989d9b6f08aSMauro Carvalho Chehab 990d9b6f08aSMauro Carvalho Chehab /* 991d9b6f08aSMauro Carvalho Chehab * As we get TMCC data from the frontend, we can better estimate the 992d9b6f08aSMauro Carvalho Chehab * BER bit counters, in order to do the BER measure during a longer 993d9b6f08aSMauro Carvalho Chehab * time. Use those data, if available, to update the bit count 994d9b6f08aSMauro Carvalho Chehab * measure. 995d9b6f08aSMauro Carvalho Chehab */ 996d9b6f08aSMauro Carvalho Chehab 997d9b6f08aSMauro Carvalho Chehab if (!state->estimated_rate[layer]) 998d9b6f08aSMauro Carvalho Chehab goto reset_measurement; 999d9b6f08aSMauro Carvalho Chehab 1000d9b6f08aSMauro Carvalho Chehab collect_rate = state->estimated_rate[layer] / 204 / 8; 1001d9b6f08aSMauro Carvalho Chehab if (collect_rate < 32) 1002d9b6f08aSMauro Carvalho Chehab collect_rate = 32; 1003d9b6f08aSMauro Carvalho Chehab if (collect_rate > 65535) 1004d9b6f08aSMauro Carvalho Chehab collect_rate = 65535; 1005d9b6f08aSMauro Carvalho Chehab if (collect_rate != counter) { 1006d9b6f08aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 1007d9b6f08aSMauro Carvalho Chehab "%s: updating postBER counter on layer %c to %d.\n", 1008d9b6f08aSMauro Carvalho Chehab __func__, 'A' + layer, collect_rate); 1009d9b6f08aSMauro Carvalho Chehab 1010d9b6f08aSMauro Carvalho Chehab /* Turn off BER after Viterbi */ 1011d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x5e, 0x00); 1012d9b6f08aSMauro Carvalho Chehab 1013d9b6f08aSMauro Carvalho Chehab /* Update counter for this layer */ 1014d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xdc + layer * 2); 1015d9b6f08aSMauro Carvalho Chehab if (rc < 0) 1016d9b6f08aSMauro Carvalho Chehab return rc; 1017d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, collect_rate >> 8); 1018d9b6f08aSMauro Carvalho Chehab if (rc < 0) 1019d9b6f08aSMauro Carvalho Chehab return rc; 1020d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xdd + layer * 2); 1021d9b6f08aSMauro Carvalho Chehab if (rc < 0) 1022d9b6f08aSMauro Carvalho Chehab return rc; 1023d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, collect_rate & 0xff); 1024d9b6f08aSMauro Carvalho Chehab if (rc < 0) 1025d9b6f08aSMauro Carvalho Chehab return rc; 1026d9b6f08aSMauro Carvalho Chehab 1027d9b6f08aSMauro Carvalho Chehab /* Turn on BER after Viterbi */ 1028d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x5e, 0x07); 1029d9b6f08aSMauro Carvalho Chehab 1030d9b6f08aSMauro Carvalho Chehab /* Reset all preBER counters */ 1031d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x5f, 0x00); 1032d9b6f08aSMauro Carvalho Chehab if (rc < 0) 1033d9b6f08aSMauro Carvalho Chehab return rc; 1034d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x5f, 0x07); 1035d9b6f08aSMauro Carvalho Chehab 1036d9b6f08aSMauro Carvalho Chehab return rc; 1037d9b6f08aSMauro Carvalho Chehab } 1038d9b6f08aSMauro Carvalho Chehab 1039d9b6f08aSMauro Carvalho Chehab reset_measurement: 1040149d518aSMauro Carvalho Chehab /* Reset counter to collect new data */ 1041ad0abbf1SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x5f); 1042149d518aSMauro Carvalho Chehab if (rc < 0) 1043149d518aSMauro Carvalho Chehab return rc; 1044ad0abbf1SMauro Carvalho Chehab val = rc; 1045ad0abbf1SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x5f, val & ~(1 << layer)); 1046ad0abbf1SMauro Carvalho Chehab if (rc < 0) 1047ad0abbf1SMauro Carvalho Chehab return rc; 1048d9b6f08aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x5f, val | (1 << layer)); 1049149d518aSMauro Carvalho Chehab 1050ad0abbf1SMauro Carvalho Chehab return rc; 1051149d518aSMauro Carvalho Chehab } 1052149d518aSMauro Carvalho Chehab 1053593ae89aSMauro Carvalho Chehab static int mb86a20s_get_blk_error(struct dvb_frontend *fe, 1054593ae89aSMauro Carvalho Chehab unsigned layer, 1055593ae89aSMauro Carvalho Chehab u32 *error, u32 *count) 1056593ae89aSMauro Carvalho Chehab { 1057593ae89aSMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 1058313cf4efSMauro Carvalho Chehab int rc, val; 1059593ae89aSMauro Carvalho Chehab u32 collect_rate; 1060593ae89aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 1061593ae89aSMauro Carvalho Chehab 10624f62a20dSMauro Carvalho Chehab if (layer >= NUM_LAYERS) 1063593ae89aSMauro Carvalho Chehab return -EINVAL; 1064593ae89aSMauro Carvalho Chehab 1065593ae89aSMauro Carvalho Chehab /* Check if the PER measures are already available */ 1066593ae89aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xb8); 1067593ae89aSMauro Carvalho Chehab if (rc < 0) 1068593ae89aSMauro Carvalho Chehab return rc; 1069593ae89aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 1070593ae89aSMauro Carvalho Chehab if (rc < 0) 1071593ae89aSMauro Carvalho Chehab return rc; 1072593ae89aSMauro Carvalho Chehab 1073593ae89aSMauro Carvalho Chehab /* Check if data is available for that layer */ 1074593ae89aSMauro Carvalho Chehab 1075593ae89aSMauro Carvalho Chehab if (!(rc & (1 << layer))) { 1076593ae89aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 1077593ae89aSMauro Carvalho Chehab "%s: block counts for layer %c aren't available yet.\n", 1078593ae89aSMauro Carvalho Chehab __func__, 'A' + layer); 1079593ae89aSMauro Carvalho Chehab return -EBUSY; 1080593ae89aSMauro Carvalho Chehab } 1081593ae89aSMauro Carvalho Chehab 1082593ae89aSMauro Carvalho Chehab /* Read Packet error Count */ 1083593ae89aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xb9 + layer * 2); 1084593ae89aSMauro Carvalho Chehab if (rc < 0) 1085593ae89aSMauro Carvalho Chehab return rc; 1086593ae89aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 1087593ae89aSMauro Carvalho Chehab if (rc < 0) 1088593ae89aSMauro Carvalho Chehab return rc; 1089593ae89aSMauro Carvalho Chehab *error = rc << 8; 1090593ae89aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xba + layer * 2); 1091593ae89aSMauro Carvalho Chehab if (rc < 0) 1092593ae89aSMauro Carvalho Chehab return rc; 1093593ae89aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 1094593ae89aSMauro Carvalho Chehab if (rc < 0) 1095593ae89aSMauro Carvalho Chehab return rc; 1096593ae89aSMauro Carvalho Chehab *error |= rc; 1097d56e326fSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s: block error for layer %c: %d.\n", 1098593ae89aSMauro Carvalho Chehab __func__, 'A' + layer, *error); 1099593ae89aSMauro Carvalho Chehab 1100593ae89aSMauro Carvalho Chehab /* Read Bit Count */ 1101593ae89aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xb2 + layer * 2); 1102593ae89aSMauro Carvalho Chehab if (rc < 0) 1103593ae89aSMauro Carvalho Chehab return rc; 1104593ae89aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 1105593ae89aSMauro Carvalho Chehab if (rc < 0) 1106593ae89aSMauro Carvalho Chehab return rc; 1107593ae89aSMauro Carvalho Chehab *count = rc << 8; 1108593ae89aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xb3 + layer * 2); 1109593ae89aSMauro Carvalho Chehab if (rc < 0) 1110593ae89aSMauro Carvalho Chehab return rc; 1111593ae89aSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 1112593ae89aSMauro Carvalho Chehab if (rc < 0) 1113593ae89aSMauro Carvalho Chehab return rc; 1114593ae89aSMauro Carvalho Chehab *count |= rc; 1115593ae89aSMauro Carvalho Chehab 1116593ae89aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 1117593ae89aSMauro Carvalho Chehab "%s: block count for layer %c: %d.\n", 1118593ae89aSMauro Carvalho Chehab __func__, 'A' + layer, *count); 1119593ae89aSMauro Carvalho Chehab 1120593ae89aSMauro Carvalho Chehab /* 1121593ae89aSMauro Carvalho Chehab * As we get TMCC data from the frontend, we can better estimate the 1122593ae89aSMauro Carvalho Chehab * BER bit counters, in order to do the BER measure during a longer 1123593ae89aSMauro Carvalho Chehab * time. Use those data, if available, to update the bit count 1124593ae89aSMauro Carvalho Chehab * measure. 1125593ae89aSMauro Carvalho Chehab */ 1126593ae89aSMauro Carvalho Chehab 1127593ae89aSMauro Carvalho Chehab if (!state->estimated_rate[layer]) 1128593ae89aSMauro Carvalho Chehab goto reset_measurement; 1129593ae89aSMauro Carvalho Chehab 1130593ae89aSMauro Carvalho Chehab collect_rate = state->estimated_rate[layer] / 204 / 8; 1131593ae89aSMauro Carvalho Chehab if (collect_rate < 32) 1132593ae89aSMauro Carvalho Chehab collect_rate = 32; 1133593ae89aSMauro Carvalho Chehab if (collect_rate > 65535) 1134593ae89aSMauro Carvalho Chehab collect_rate = 65535; 1135593ae89aSMauro Carvalho Chehab 1136593ae89aSMauro Carvalho Chehab if (collect_rate != *count) { 1137593ae89aSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 1138593ae89aSMauro Carvalho Chehab "%s: updating PER counter on layer %c to %d.\n", 1139593ae89aSMauro Carvalho Chehab __func__, 'A' + layer, collect_rate); 1140313cf4efSMauro Carvalho Chehab 1141313cf4efSMauro Carvalho Chehab /* Stop PER measurement */ 1142313cf4efSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xb0); 1143313cf4efSMauro Carvalho Chehab if (rc < 0) 1144313cf4efSMauro Carvalho Chehab return rc; 1145313cf4efSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, 0x00); 1146313cf4efSMauro Carvalho Chehab if (rc < 0) 1147313cf4efSMauro Carvalho Chehab return rc; 1148313cf4efSMauro Carvalho Chehab 1149313cf4efSMauro Carvalho Chehab /* Update this layer's counter */ 1150593ae89aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xb2 + layer * 2); 1151593ae89aSMauro Carvalho Chehab if (rc < 0) 1152593ae89aSMauro Carvalho Chehab return rc; 1153593ae89aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, collect_rate >> 8); 1154593ae89aSMauro Carvalho Chehab if (rc < 0) 1155593ae89aSMauro Carvalho Chehab return rc; 1156593ae89aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xb3 + layer * 2); 1157593ae89aSMauro Carvalho Chehab if (rc < 0) 1158593ae89aSMauro Carvalho Chehab return rc; 1159593ae89aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, collect_rate & 0xff); 1160593ae89aSMauro Carvalho Chehab if (rc < 0) 1161593ae89aSMauro Carvalho Chehab return rc; 1162313cf4efSMauro Carvalho Chehab 1163313cf4efSMauro Carvalho Chehab /* start PER measurement */ 1164313cf4efSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xb0); 1165313cf4efSMauro Carvalho Chehab if (rc < 0) 1166313cf4efSMauro Carvalho Chehab return rc; 1167313cf4efSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, 0x07); 1168313cf4efSMauro Carvalho Chehab if (rc < 0) 1169313cf4efSMauro Carvalho Chehab return rc; 1170313cf4efSMauro Carvalho Chehab 1171313cf4efSMauro Carvalho Chehab /* Reset all counters to collect new data */ 1172313cf4efSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xb1); 1173313cf4efSMauro Carvalho Chehab if (rc < 0) 1174313cf4efSMauro Carvalho Chehab return rc; 1175313cf4efSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, 0x07); 1176313cf4efSMauro Carvalho Chehab if (rc < 0) 1177313cf4efSMauro Carvalho Chehab return rc; 1178313cf4efSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, 0x00); 1179313cf4efSMauro Carvalho Chehab 1180313cf4efSMauro Carvalho Chehab return rc; 1181593ae89aSMauro Carvalho Chehab } 1182593ae89aSMauro Carvalho Chehab 1183593ae89aSMauro Carvalho Chehab reset_measurement: 1184593ae89aSMauro Carvalho Chehab /* Reset counter to collect new data */ 1185593ae89aSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xb1); 1186593ae89aSMauro Carvalho Chehab if (rc < 0) 1187593ae89aSMauro Carvalho Chehab return rc; 1188313cf4efSMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 1189593ae89aSMauro Carvalho Chehab if (rc < 0) 1190593ae89aSMauro Carvalho Chehab return rc; 1191313cf4efSMauro Carvalho Chehab val = rc; 1192313cf4efSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, val | (1 << layer)); 1193593ae89aSMauro Carvalho Chehab if (rc < 0) 1194593ae89aSMauro Carvalho Chehab return rc; 1195313cf4efSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, val & ~(1 << layer)); 1196593ae89aSMauro Carvalho Chehab 1197313cf4efSMauro Carvalho Chehab return rc; 1198593ae89aSMauro Carvalho Chehab } 1199593ae89aSMauro Carvalho Chehab 120025188bd0SMauro Carvalho Chehab struct linear_segments { 120125188bd0SMauro Carvalho Chehab unsigned x, y; 120225188bd0SMauro Carvalho Chehab }; 120325188bd0SMauro Carvalho Chehab 120425188bd0SMauro Carvalho Chehab /* 120525188bd0SMauro Carvalho Chehab * All tables below return a dB/1000 measurement 120625188bd0SMauro Carvalho Chehab */ 120725188bd0SMauro Carvalho Chehab 1208ce08131cSHans Verkuil static const struct linear_segments cnr_to_db_table[] = { 120925188bd0SMauro Carvalho Chehab { 19648, 0}, 121025188bd0SMauro Carvalho Chehab { 18187, 1000}, 121125188bd0SMauro Carvalho Chehab { 16534, 2000}, 121225188bd0SMauro Carvalho Chehab { 14823, 3000}, 121325188bd0SMauro Carvalho Chehab { 13161, 4000}, 121425188bd0SMauro Carvalho Chehab { 11622, 5000}, 121525188bd0SMauro Carvalho Chehab { 10279, 6000}, 121625188bd0SMauro Carvalho Chehab { 9089, 7000}, 121725188bd0SMauro Carvalho Chehab { 8042, 8000}, 121825188bd0SMauro Carvalho Chehab { 7137, 9000}, 121925188bd0SMauro Carvalho Chehab { 6342, 10000}, 122025188bd0SMauro Carvalho Chehab { 5641, 11000}, 122125188bd0SMauro Carvalho Chehab { 5030, 12000}, 122225188bd0SMauro Carvalho Chehab { 4474, 13000}, 122325188bd0SMauro Carvalho Chehab { 3988, 14000}, 122425188bd0SMauro Carvalho Chehab { 3556, 15000}, 122525188bd0SMauro Carvalho Chehab { 3180, 16000}, 122625188bd0SMauro Carvalho Chehab { 2841, 17000}, 122725188bd0SMauro Carvalho Chehab { 2541, 18000}, 122825188bd0SMauro Carvalho Chehab { 2276, 19000}, 122925188bd0SMauro Carvalho Chehab { 2038, 20000}, 123025188bd0SMauro Carvalho Chehab { 1800, 21000}, 123125188bd0SMauro Carvalho Chehab { 1625, 22000}, 123225188bd0SMauro Carvalho Chehab { 1462, 23000}, 123325188bd0SMauro Carvalho Chehab { 1324, 24000}, 123425188bd0SMauro Carvalho Chehab { 1175, 25000}, 123525188bd0SMauro Carvalho Chehab { 1063, 26000}, 123625188bd0SMauro Carvalho Chehab { 980, 27000}, 123725188bd0SMauro Carvalho Chehab { 907, 28000}, 123825188bd0SMauro Carvalho Chehab { 840, 29000}, 123925188bd0SMauro Carvalho Chehab { 788, 30000}, 124025188bd0SMauro Carvalho Chehab }; 124125188bd0SMauro Carvalho Chehab 1242ce08131cSHans Verkuil static const struct linear_segments cnr_64qam_table[] = { 124325188bd0SMauro Carvalho Chehab { 3922688, 0}, 124425188bd0SMauro Carvalho Chehab { 3920384, 1000}, 124525188bd0SMauro Carvalho Chehab { 3902720, 2000}, 124625188bd0SMauro Carvalho Chehab { 3894784, 3000}, 124725188bd0SMauro Carvalho Chehab { 3882496, 4000}, 124825188bd0SMauro Carvalho Chehab { 3872768, 5000}, 124925188bd0SMauro Carvalho Chehab { 3858944, 6000}, 125025188bd0SMauro Carvalho Chehab { 3851520, 7000}, 125125188bd0SMauro Carvalho Chehab { 3838976, 8000}, 125225188bd0SMauro Carvalho Chehab { 3829248, 9000}, 125325188bd0SMauro Carvalho Chehab { 3818240, 10000}, 125425188bd0SMauro Carvalho Chehab { 3806976, 11000}, 125525188bd0SMauro Carvalho Chehab { 3791872, 12000}, 125625188bd0SMauro Carvalho Chehab { 3767040, 13000}, 125725188bd0SMauro Carvalho Chehab { 3720960, 14000}, 125825188bd0SMauro Carvalho Chehab { 3637504, 15000}, 125925188bd0SMauro Carvalho Chehab { 3498496, 16000}, 126025188bd0SMauro Carvalho Chehab { 3296000, 17000}, 126125188bd0SMauro Carvalho Chehab { 3031040, 18000}, 126225188bd0SMauro Carvalho Chehab { 2715392, 19000}, 126325188bd0SMauro Carvalho Chehab { 2362624, 20000}, 126425188bd0SMauro Carvalho Chehab { 1963264, 21000}, 126525188bd0SMauro Carvalho Chehab { 1649664, 22000}, 126625188bd0SMauro Carvalho Chehab { 1366784, 23000}, 126725188bd0SMauro Carvalho Chehab { 1120768, 24000}, 126825188bd0SMauro Carvalho Chehab { 890880, 25000}, 126925188bd0SMauro Carvalho Chehab { 723456, 26000}, 127025188bd0SMauro Carvalho Chehab { 612096, 27000}, 127125188bd0SMauro Carvalho Chehab { 518912, 28000}, 127225188bd0SMauro Carvalho Chehab { 448256, 29000}, 127325188bd0SMauro Carvalho Chehab { 388864, 30000}, 127425188bd0SMauro Carvalho Chehab }; 127525188bd0SMauro Carvalho Chehab 1276ce08131cSHans Verkuil static const struct linear_segments cnr_16qam_table[] = { 127725188bd0SMauro Carvalho Chehab { 5314816, 0}, 127825188bd0SMauro Carvalho Chehab { 5219072, 1000}, 127925188bd0SMauro Carvalho Chehab { 5118720, 2000}, 128025188bd0SMauro Carvalho Chehab { 4998912, 3000}, 128125188bd0SMauro Carvalho Chehab { 4875520, 4000}, 128225188bd0SMauro Carvalho Chehab { 4736000, 5000}, 128325188bd0SMauro Carvalho Chehab { 4604160, 6000}, 128425188bd0SMauro Carvalho Chehab { 4458752, 7000}, 128525188bd0SMauro Carvalho Chehab { 4300288, 8000}, 128625188bd0SMauro Carvalho Chehab { 4092928, 9000}, 128725188bd0SMauro Carvalho Chehab { 3836160, 10000}, 128825188bd0SMauro Carvalho Chehab { 3521024, 11000}, 128925188bd0SMauro Carvalho Chehab { 3155968, 12000}, 129025188bd0SMauro Carvalho Chehab { 2756864, 13000}, 129125188bd0SMauro Carvalho Chehab { 2347008, 14000}, 129225188bd0SMauro Carvalho Chehab { 1955072, 15000}, 129325188bd0SMauro Carvalho Chehab { 1593600, 16000}, 129425188bd0SMauro Carvalho Chehab { 1297920, 17000}, 129525188bd0SMauro Carvalho Chehab { 1043968, 18000}, 129625188bd0SMauro Carvalho Chehab { 839680, 19000}, 129725188bd0SMauro Carvalho Chehab { 672256, 20000}, 129825188bd0SMauro Carvalho Chehab { 523008, 21000}, 129925188bd0SMauro Carvalho Chehab { 424704, 22000}, 130025188bd0SMauro Carvalho Chehab { 345088, 23000}, 130125188bd0SMauro Carvalho Chehab { 280064, 24000}, 130225188bd0SMauro Carvalho Chehab { 221440, 25000}, 130325188bd0SMauro Carvalho Chehab { 179712, 26000}, 130425188bd0SMauro Carvalho Chehab { 151040, 27000}, 130525188bd0SMauro Carvalho Chehab { 128512, 28000}, 130625188bd0SMauro Carvalho Chehab { 110080, 29000}, 130725188bd0SMauro Carvalho Chehab { 95744, 30000}, 130825188bd0SMauro Carvalho Chehab }; 130925188bd0SMauro Carvalho Chehab 1310ce08131cSHans Verkuil static const struct linear_segments cnr_qpsk_table[] = { 131125188bd0SMauro Carvalho Chehab { 2834176, 0}, 131225188bd0SMauro Carvalho Chehab { 2683648, 1000}, 131325188bd0SMauro Carvalho Chehab { 2536960, 2000}, 131425188bd0SMauro Carvalho Chehab { 2391808, 3000}, 131525188bd0SMauro Carvalho Chehab { 2133248, 4000}, 131625188bd0SMauro Carvalho Chehab { 1906176, 5000}, 131725188bd0SMauro Carvalho Chehab { 1666560, 6000}, 131825188bd0SMauro Carvalho Chehab { 1422080, 7000}, 131925188bd0SMauro Carvalho Chehab { 1189632, 8000}, 132025188bd0SMauro Carvalho Chehab { 976384, 9000}, 132125188bd0SMauro Carvalho Chehab { 790272, 10000}, 132225188bd0SMauro Carvalho Chehab { 633344, 11000}, 132325188bd0SMauro Carvalho Chehab { 505600, 12000}, 132425188bd0SMauro Carvalho Chehab { 402944, 13000}, 132525188bd0SMauro Carvalho Chehab { 320768, 14000}, 132625188bd0SMauro Carvalho Chehab { 255488, 15000}, 132725188bd0SMauro Carvalho Chehab { 204032, 16000}, 132825188bd0SMauro Carvalho Chehab { 163072, 17000}, 132925188bd0SMauro Carvalho Chehab { 130304, 18000}, 133025188bd0SMauro Carvalho Chehab { 105216, 19000}, 133125188bd0SMauro Carvalho Chehab { 83456, 20000}, 133225188bd0SMauro Carvalho Chehab { 65024, 21000}, 133325188bd0SMauro Carvalho Chehab { 52480, 22000}, 133425188bd0SMauro Carvalho Chehab { 42752, 23000}, 133525188bd0SMauro Carvalho Chehab { 34560, 24000}, 133625188bd0SMauro Carvalho Chehab { 27136, 25000}, 133725188bd0SMauro Carvalho Chehab { 22016, 26000}, 133825188bd0SMauro Carvalho Chehab { 18432, 27000}, 133925188bd0SMauro Carvalho Chehab { 15616, 28000}, 134025188bd0SMauro Carvalho Chehab { 13312, 29000}, 134125188bd0SMauro Carvalho Chehab { 11520, 30000}, 134225188bd0SMauro Carvalho Chehab }; 134325188bd0SMauro Carvalho Chehab 1344ce08131cSHans Verkuil static u32 interpolate_value(u32 value, const struct linear_segments *segments, 134525188bd0SMauro Carvalho Chehab unsigned len) 134625188bd0SMauro Carvalho Chehab { 134725188bd0SMauro Carvalho Chehab u64 tmp64; 134825188bd0SMauro Carvalho Chehab u32 dx, dy; 134925188bd0SMauro Carvalho Chehab int i, ret; 135025188bd0SMauro Carvalho Chehab 135125188bd0SMauro Carvalho Chehab if (value >= segments[0].x) 135225188bd0SMauro Carvalho Chehab return segments[0].y; 135325188bd0SMauro Carvalho Chehab if (value < segments[len-1].x) 135425188bd0SMauro Carvalho Chehab return segments[len-1].y; 135525188bd0SMauro Carvalho Chehab 135625188bd0SMauro Carvalho Chehab for (i = 1; i < len - 1; i++) { 135725188bd0SMauro Carvalho Chehab /* If value is identical, no need to interpolate */ 135825188bd0SMauro Carvalho Chehab if (value == segments[i].x) 135925188bd0SMauro Carvalho Chehab return segments[i].y; 136025188bd0SMauro Carvalho Chehab if (value > segments[i].x) 136125188bd0SMauro Carvalho Chehab break; 136225188bd0SMauro Carvalho Chehab } 136325188bd0SMauro Carvalho Chehab 136425188bd0SMauro Carvalho Chehab /* Linear interpolation between the two (x,y) points */ 136525188bd0SMauro Carvalho Chehab dy = segments[i].y - segments[i - 1].y; 136625188bd0SMauro Carvalho Chehab dx = segments[i - 1].x - segments[i].x; 136725188bd0SMauro Carvalho Chehab tmp64 = value - segments[i].x; 136825188bd0SMauro Carvalho Chehab tmp64 *= dy; 136925188bd0SMauro Carvalho Chehab do_div(tmp64, dx); 137025188bd0SMauro Carvalho Chehab ret = segments[i].y - tmp64; 137125188bd0SMauro Carvalho Chehab 137225188bd0SMauro Carvalho Chehab return ret; 137325188bd0SMauro Carvalho Chehab } 137425188bd0SMauro Carvalho Chehab 137525188bd0SMauro Carvalho Chehab static int mb86a20s_get_main_CNR(struct dvb_frontend *fe) 137625188bd0SMauro Carvalho Chehab { 137725188bd0SMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 137825188bd0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 137925188bd0SMauro Carvalho Chehab u32 cnr_linear, cnr; 138025188bd0SMauro Carvalho Chehab int rc, val; 138125188bd0SMauro Carvalho Chehab 138225188bd0SMauro Carvalho Chehab /* Check if CNR is available */ 138325188bd0SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x45); 138425188bd0SMauro Carvalho Chehab if (rc < 0) 138525188bd0SMauro Carvalho Chehab return rc; 138625188bd0SMauro Carvalho Chehab 138725188bd0SMauro Carvalho Chehab if (!(rc & 0x40)) { 1388d56e326fSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s: CNR is not available yet.\n", 138925188bd0SMauro Carvalho Chehab __func__); 139025188bd0SMauro Carvalho Chehab return -EBUSY; 139125188bd0SMauro Carvalho Chehab } 139225188bd0SMauro Carvalho Chehab val = rc; 139325188bd0SMauro Carvalho Chehab 139425188bd0SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x46); 139525188bd0SMauro Carvalho Chehab if (rc < 0) 139625188bd0SMauro Carvalho Chehab return rc; 139725188bd0SMauro Carvalho Chehab cnr_linear = rc << 8; 139825188bd0SMauro Carvalho Chehab 139925188bd0SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x46); 140025188bd0SMauro Carvalho Chehab if (rc < 0) 140125188bd0SMauro Carvalho Chehab return rc; 140225188bd0SMauro Carvalho Chehab cnr_linear |= rc; 140325188bd0SMauro Carvalho Chehab 140425188bd0SMauro Carvalho Chehab cnr = interpolate_value(cnr_linear, 140525188bd0SMauro Carvalho Chehab cnr_to_db_table, ARRAY_SIZE(cnr_to_db_table)); 140625188bd0SMauro Carvalho Chehab 140725188bd0SMauro Carvalho Chehab c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 140825188bd0SMauro Carvalho Chehab c->cnr.stat[0].svalue = cnr; 140925188bd0SMauro Carvalho Chehab 141025188bd0SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s: CNR is %d.%03d dB (%d)\n", 141125188bd0SMauro Carvalho Chehab __func__, cnr / 1000, cnr % 1000, cnr_linear); 141225188bd0SMauro Carvalho Chehab 141325188bd0SMauro Carvalho Chehab /* CNR counter reset */ 141425188bd0SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x45, val | 0x10); 141525188bd0SMauro Carvalho Chehab if (rc < 0) 141625188bd0SMauro Carvalho Chehab return rc; 141725188bd0SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x45, val & 0x6f); 141825188bd0SMauro Carvalho Chehab 141925188bd0SMauro Carvalho Chehab return rc; 142025188bd0SMauro Carvalho Chehab } 142125188bd0SMauro Carvalho Chehab 1422593ae89aSMauro Carvalho Chehab static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe) 142325188bd0SMauro Carvalho Chehab { 142425188bd0SMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 142525188bd0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 142625188bd0SMauro Carvalho Chehab u32 mer, cnr; 14275cb88ca8SMauro Carvalho Chehab int rc, val, layer; 1428ce08131cSHans Verkuil const struct linear_segments *segs; 142925188bd0SMauro Carvalho Chehab unsigned segs_len; 143025188bd0SMauro Carvalho Chehab 143125188bd0SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 143225188bd0SMauro Carvalho Chehab 143325188bd0SMauro Carvalho Chehab /* Check if the measures are already available */ 143425188bd0SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0x5b); 143525188bd0SMauro Carvalho Chehab if (rc < 0) 143625188bd0SMauro Carvalho Chehab return rc; 143725188bd0SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 143825188bd0SMauro Carvalho Chehab if (rc < 0) 143925188bd0SMauro Carvalho Chehab return rc; 144025188bd0SMauro Carvalho Chehab 144125188bd0SMauro Carvalho Chehab /* Check if data is available */ 144225188bd0SMauro Carvalho Chehab if (!(rc & 0x01)) { 1443d56e326fSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 144425188bd0SMauro Carvalho Chehab "%s: MER measures aren't available yet.\n", __func__); 144525188bd0SMauro Carvalho Chehab return -EBUSY; 144625188bd0SMauro Carvalho Chehab } 144725188bd0SMauro Carvalho Chehab 144825188bd0SMauro Carvalho Chehab /* Read all layers */ 14495cb88ca8SMauro Carvalho Chehab for (layer = 0; layer < NUM_LAYERS; layer++) { 14505cb88ca8SMauro Carvalho Chehab if (!(c->isdbt_layer_enabled & (1 << layer))) { 14515cb88ca8SMauro Carvalho Chehab c->cnr.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 145225188bd0SMauro Carvalho Chehab continue; 145325188bd0SMauro Carvalho Chehab } 145425188bd0SMauro Carvalho Chehab 14555cb88ca8SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0x52 + layer * 3); 145625188bd0SMauro Carvalho Chehab if (rc < 0) 145725188bd0SMauro Carvalho Chehab return rc; 145825188bd0SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 145925188bd0SMauro Carvalho Chehab if (rc < 0) 146025188bd0SMauro Carvalho Chehab return rc; 146125188bd0SMauro Carvalho Chehab mer = rc << 16; 14625cb88ca8SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0x53 + layer * 3); 146325188bd0SMauro Carvalho Chehab if (rc < 0) 146425188bd0SMauro Carvalho Chehab return rc; 146525188bd0SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 146625188bd0SMauro Carvalho Chehab if (rc < 0) 146725188bd0SMauro Carvalho Chehab return rc; 146825188bd0SMauro Carvalho Chehab mer |= rc << 8; 14695cb88ca8SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0x54 + layer * 3); 147025188bd0SMauro Carvalho Chehab if (rc < 0) 147125188bd0SMauro Carvalho Chehab return rc; 147225188bd0SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 147325188bd0SMauro Carvalho Chehab if (rc < 0) 147425188bd0SMauro Carvalho Chehab return rc; 147525188bd0SMauro Carvalho Chehab mer |= rc; 147625188bd0SMauro Carvalho Chehab 14775cb88ca8SMauro Carvalho Chehab switch (c->layer[layer].modulation) { 147825188bd0SMauro Carvalho Chehab case DQPSK: 147925188bd0SMauro Carvalho Chehab case QPSK: 148025188bd0SMauro Carvalho Chehab segs = cnr_qpsk_table; 148125188bd0SMauro Carvalho Chehab segs_len = ARRAY_SIZE(cnr_qpsk_table); 148225188bd0SMauro Carvalho Chehab break; 148325188bd0SMauro Carvalho Chehab case QAM_16: 148425188bd0SMauro Carvalho Chehab segs = cnr_16qam_table; 148525188bd0SMauro Carvalho Chehab segs_len = ARRAY_SIZE(cnr_16qam_table); 148625188bd0SMauro Carvalho Chehab break; 148725188bd0SMauro Carvalho Chehab default: 148825188bd0SMauro Carvalho Chehab case QAM_64: 148925188bd0SMauro Carvalho Chehab segs = cnr_64qam_table; 149025188bd0SMauro Carvalho Chehab segs_len = ARRAY_SIZE(cnr_64qam_table); 149125188bd0SMauro Carvalho Chehab break; 149225188bd0SMauro Carvalho Chehab } 149325188bd0SMauro Carvalho Chehab cnr = interpolate_value(mer, segs, segs_len); 149425188bd0SMauro Carvalho Chehab 14955cb88ca8SMauro Carvalho Chehab c->cnr.stat[1 + layer].scale = FE_SCALE_DECIBEL; 14965cb88ca8SMauro Carvalho Chehab c->cnr.stat[1 + layer].svalue = cnr; 149725188bd0SMauro Carvalho Chehab 149825188bd0SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, 149925188bd0SMauro Carvalho Chehab "%s: CNR for layer %c is %d.%03d dB (MER = %d).\n", 15005cb88ca8SMauro Carvalho Chehab __func__, 'A' + layer, cnr / 1000, cnr % 1000, mer); 150125188bd0SMauro Carvalho Chehab 150225188bd0SMauro Carvalho Chehab } 150325188bd0SMauro Carvalho Chehab 150425188bd0SMauro Carvalho Chehab /* Start a new MER measurement */ 150525188bd0SMauro Carvalho Chehab /* MER counter reset */ 150625188bd0SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0x50); 150725188bd0SMauro Carvalho Chehab if (rc < 0) 150825188bd0SMauro Carvalho Chehab return rc; 150925188bd0SMauro Carvalho Chehab rc = mb86a20s_readreg(state, 0x51); 151025188bd0SMauro Carvalho Chehab if (rc < 0) 151125188bd0SMauro Carvalho Chehab return rc; 151225188bd0SMauro Carvalho Chehab val = rc; 151325188bd0SMauro Carvalho Chehab 151425188bd0SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, val | 0x01); 151525188bd0SMauro Carvalho Chehab if (rc < 0) 151625188bd0SMauro Carvalho Chehab return rc; 151725188bd0SMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, val & 0x06); 151825188bd0SMauro Carvalho Chehab if (rc < 0) 151925188bd0SMauro Carvalho Chehab return rc; 152025188bd0SMauro Carvalho Chehab 152125188bd0SMauro Carvalho Chehab return 0; 152225188bd0SMauro Carvalho Chehab } 152325188bd0SMauro Carvalho Chehab 152409b6d21eSMauro Carvalho Chehab static void mb86a20s_stats_not_ready(struct dvb_frontend *fe) 152509b6d21eSMauro Carvalho Chehab { 152609b6d21eSMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 152709b6d21eSMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 15285cb88ca8SMauro Carvalho Chehab int layer; 152909b6d21eSMauro Carvalho Chehab 153009b6d21eSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 153109b6d21eSMauro Carvalho Chehab 153209b6d21eSMauro Carvalho Chehab /* Fill the length of each status counter */ 153309b6d21eSMauro Carvalho Chehab 153409b6d21eSMauro Carvalho Chehab /* Only global stats */ 153509b6d21eSMauro Carvalho Chehab c->strength.len = 1; 153609b6d21eSMauro Carvalho Chehab 153709b6d21eSMauro Carvalho Chehab /* Per-layer stats - 3 layers + global */ 15384f62a20dSMauro Carvalho Chehab c->cnr.len = NUM_LAYERS + 1; 15394f62a20dSMauro Carvalho Chehab c->pre_bit_error.len = NUM_LAYERS + 1; 15404f62a20dSMauro Carvalho Chehab c->pre_bit_count.len = NUM_LAYERS + 1; 15414f62a20dSMauro Carvalho Chehab c->post_bit_error.len = NUM_LAYERS + 1; 15424f62a20dSMauro Carvalho Chehab c->post_bit_count.len = NUM_LAYERS + 1; 15434f62a20dSMauro Carvalho Chehab c->block_error.len = NUM_LAYERS + 1; 15444f62a20dSMauro Carvalho Chehab c->block_count.len = NUM_LAYERS + 1; 154509b6d21eSMauro Carvalho Chehab 154609b6d21eSMauro Carvalho Chehab /* Signal is always available */ 154709b6d21eSMauro Carvalho Chehab c->strength.stat[0].scale = FE_SCALE_RELATIVE; 154809b6d21eSMauro Carvalho Chehab c->strength.stat[0].uvalue = 0; 154909b6d21eSMauro Carvalho Chehab 155009b6d21eSMauro Carvalho Chehab /* Put all of them at FE_SCALE_NOT_AVAILABLE */ 15515cb88ca8SMauro Carvalho Chehab for (layer = 0; layer < NUM_LAYERS + 1; layer++) { 15525cb88ca8SMauro Carvalho Chehab c->cnr.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 15535cb88ca8SMauro Carvalho Chehab c->pre_bit_error.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 15545cb88ca8SMauro Carvalho Chehab c->pre_bit_count.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 15555cb88ca8SMauro Carvalho Chehab c->post_bit_error.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 15565cb88ca8SMauro Carvalho Chehab c->post_bit_count.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 15575cb88ca8SMauro Carvalho Chehab c->block_error.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 15585cb88ca8SMauro Carvalho Chehab c->block_count.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; 155909b6d21eSMauro Carvalho Chehab } 156009b6d21eSMauro Carvalho Chehab } 156109b6d21eSMauro Carvalho Chehab 156215b1c5a0SMauro Carvalho Chehab static int mb86a20s_get_stats(struct dvb_frontend *fe, int status_nr) 1563149d518aSMauro Carvalho Chehab { 1564149d518aSMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 1565149d518aSMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 15665cb88ca8SMauro Carvalho Chehab int rc = 0, layer; 1567149d518aSMauro Carvalho Chehab u32 bit_error = 0, bit_count = 0; 1568149d518aSMauro Carvalho Chehab u32 t_pre_bit_error = 0, t_pre_bit_count = 0; 1569d9b6f08aSMauro Carvalho Chehab u32 t_post_bit_error = 0, t_post_bit_count = 0; 1570593ae89aSMauro Carvalho Chehab u32 block_error = 0, block_count = 0; 1571593ae89aSMauro Carvalho Chehab u32 t_block_error = 0, t_block_count = 0; 1572*190e2e11SMauro Carvalho Chehab int pre_ber_layers = 0, post_ber_layers = 0; 1573d9b6f08aSMauro Carvalho Chehab int per_layers = 0; 1574149d518aSMauro Carvalho Chehab 157525188bd0SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 157625188bd0SMauro Carvalho Chehab 157725188bd0SMauro Carvalho Chehab mb86a20s_get_main_CNR(fe); 157825188bd0SMauro Carvalho Chehab 1579149d518aSMauro Carvalho Chehab /* Get per-layer stats */ 1580593ae89aSMauro Carvalho Chehab mb86a20s_get_blk_error_layer_CNR(fe); 158125188bd0SMauro Carvalho Chehab 158215b1c5a0SMauro Carvalho Chehab /* 158315b1c5a0SMauro Carvalho Chehab * At state 7, only CNR is available 158415b1c5a0SMauro Carvalho Chehab * For BER measures, state=9 is required 158515b1c5a0SMauro Carvalho Chehab * FIXME: we may get MER measures with state=8 158615b1c5a0SMauro Carvalho Chehab */ 158715b1c5a0SMauro Carvalho Chehab if (status_nr < 9) 158815b1c5a0SMauro Carvalho Chehab return 0; 158915b1c5a0SMauro Carvalho Chehab 15905cb88ca8SMauro Carvalho Chehab for (layer = 0; layer < NUM_LAYERS; layer++) { 15915cb88ca8SMauro Carvalho Chehab if (c->isdbt_layer_enabled & (1 << layer)) { 1592149d518aSMauro Carvalho Chehab /* Handle BER before vterbi */ 15935cb88ca8SMauro Carvalho Chehab rc = mb86a20s_get_pre_ber(fe, layer, 1594ad0abbf1SMauro Carvalho Chehab &bit_error, &bit_count); 1595149d518aSMauro Carvalho Chehab if (rc >= 0) { 15965cb88ca8SMauro Carvalho Chehab c->pre_bit_error.stat[1 + layer].scale = FE_SCALE_COUNTER; 15975cb88ca8SMauro Carvalho Chehab c->pre_bit_error.stat[1 + layer].uvalue += bit_error; 15985cb88ca8SMauro Carvalho Chehab c->pre_bit_count.stat[1 + layer].scale = FE_SCALE_COUNTER; 15995cb88ca8SMauro Carvalho Chehab c->pre_bit_count.stat[1 + layer].uvalue += bit_count; 1600149d518aSMauro Carvalho Chehab } else if (rc != -EBUSY) { 1601149d518aSMauro Carvalho Chehab /* 1602149d518aSMauro Carvalho Chehab * If an I/O error happened, 1603149d518aSMauro Carvalho Chehab * measures are now unavailable 1604149d518aSMauro Carvalho Chehab */ 16055cb88ca8SMauro Carvalho Chehab c->pre_bit_error.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 16065cb88ca8SMauro Carvalho Chehab c->pre_bit_count.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 1607149d518aSMauro Carvalho Chehab dev_err(&state->i2c->dev, 1608149d518aSMauro Carvalho Chehab "%s: Can't get BER for layer %c (error %d).\n", 16095cb88ca8SMauro Carvalho Chehab __func__, 'A' + layer, rc); 1610149d518aSMauro Carvalho Chehab } 16115cb88ca8SMauro Carvalho Chehab if (c->block_error.stat[1 + layer].scale != FE_SCALE_NOT_AVAILABLE) 1612d9b6f08aSMauro Carvalho Chehab pre_ber_layers++; 1613d9b6f08aSMauro Carvalho Chehab 1614d9b6f08aSMauro Carvalho Chehab /* Handle BER post vterbi */ 16155cb88ca8SMauro Carvalho Chehab rc = mb86a20s_get_post_ber(fe, layer, 1616d9b6f08aSMauro Carvalho Chehab &bit_error, &bit_count); 1617d9b6f08aSMauro Carvalho Chehab if (rc >= 0) { 16185cb88ca8SMauro Carvalho Chehab c->post_bit_error.stat[1 + layer].scale = FE_SCALE_COUNTER; 16195cb88ca8SMauro Carvalho Chehab c->post_bit_error.stat[1 + layer].uvalue += bit_error; 16205cb88ca8SMauro Carvalho Chehab c->post_bit_count.stat[1 + layer].scale = FE_SCALE_COUNTER; 16215cb88ca8SMauro Carvalho Chehab c->post_bit_count.stat[1 + layer].uvalue += bit_count; 1622d9b6f08aSMauro Carvalho Chehab } else if (rc != -EBUSY) { 1623d9b6f08aSMauro Carvalho Chehab /* 1624d9b6f08aSMauro Carvalho Chehab * If an I/O error happened, 1625d9b6f08aSMauro Carvalho Chehab * measures are now unavailable 1626d9b6f08aSMauro Carvalho Chehab */ 16275cb88ca8SMauro Carvalho Chehab c->post_bit_error.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 16285cb88ca8SMauro Carvalho Chehab c->post_bit_count.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 1629d9b6f08aSMauro Carvalho Chehab dev_err(&state->i2c->dev, 1630d9b6f08aSMauro Carvalho Chehab "%s: Can't get BER for layer %c (error %d).\n", 16315cb88ca8SMauro Carvalho Chehab __func__, 'A' + layer, rc); 1632d9b6f08aSMauro Carvalho Chehab } 16335cb88ca8SMauro Carvalho Chehab if (c->block_error.stat[1 + layer].scale != FE_SCALE_NOT_AVAILABLE) 1634d9b6f08aSMauro Carvalho Chehab post_ber_layers++; 1635149d518aSMauro Carvalho Chehab 1636593ae89aSMauro Carvalho Chehab /* Handle Block errors for PER/UCB reports */ 16375cb88ca8SMauro Carvalho Chehab rc = mb86a20s_get_blk_error(fe, layer, 1638593ae89aSMauro Carvalho Chehab &block_error, 1639593ae89aSMauro Carvalho Chehab &block_count); 1640593ae89aSMauro Carvalho Chehab if (rc >= 0) { 16415cb88ca8SMauro Carvalho Chehab c->block_error.stat[1 + layer].scale = FE_SCALE_COUNTER; 16425cb88ca8SMauro Carvalho Chehab c->block_error.stat[1 + layer].uvalue += block_error; 16435cb88ca8SMauro Carvalho Chehab c->block_count.stat[1 + layer].scale = FE_SCALE_COUNTER; 16445cb88ca8SMauro Carvalho Chehab c->block_count.stat[1 + layer].uvalue += block_count; 1645593ae89aSMauro Carvalho Chehab } else if (rc != -EBUSY) { 1646593ae89aSMauro Carvalho Chehab /* 1647593ae89aSMauro Carvalho Chehab * If an I/O error happened, 1648593ae89aSMauro Carvalho Chehab * measures are now unavailable 1649593ae89aSMauro Carvalho Chehab */ 16505cb88ca8SMauro Carvalho Chehab c->block_error.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 16515cb88ca8SMauro Carvalho Chehab c->block_count.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; 1652593ae89aSMauro Carvalho Chehab dev_err(&state->i2c->dev, 1653593ae89aSMauro Carvalho Chehab "%s: Can't get PER for layer %c (error %d).\n", 16545cb88ca8SMauro Carvalho Chehab __func__, 'A' + layer, rc); 1655593ae89aSMauro Carvalho Chehab 1656593ae89aSMauro Carvalho Chehab } 16575cb88ca8SMauro Carvalho Chehab if (c->block_error.stat[1 + layer].scale != FE_SCALE_NOT_AVAILABLE) 1658593ae89aSMauro Carvalho Chehab per_layers++; 1659593ae89aSMauro Carvalho Chehab 1660d9b6f08aSMauro Carvalho Chehab /* Update total preBER */ 16615cb88ca8SMauro Carvalho Chehab t_pre_bit_error += c->pre_bit_error.stat[1 + layer].uvalue; 16625cb88ca8SMauro Carvalho Chehab t_pre_bit_count += c->pre_bit_count.stat[1 + layer].uvalue; 1663593ae89aSMauro Carvalho Chehab 1664d9b6f08aSMauro Carvalho Chehab /* Update total postBER */ 16655cb88ca8SMauro Carvalho Chehab t_post_bit_error += c->post_bit_error.stat[1 + layer].uvalue; 16665cb88ca8SMauro Carvalho Chehab t_post_bit_count += c->post_bit_count.stat[1 + layer].uvalue; 1667d9b6f08aSMauro Carvalho Chehab 1668593ae89aSMauro Carvalho Chehab /* Update total PER */ 16695cb88ca8SMauro Carvalho Chehab t_block_error += c->block_error.stat[1 + layer].uvalue; 16705cb88ca8SMauro Carvalho Chehab t_block_count += c->block_count.stat[1 + layer].uvalue; 1671149d518aSMauro Carvalho Chehab } 1672149d518aSMauro Carvalho Chehab } 1673149d518aSMauro Carvalho Chehab 1674149d518aSMauro Carvalho Chehab /* 1675149d518aSMauro Carvalho Chehab * Start showing global count if at least one error count is 1676149d518aSMauro Carvalho Chehab * available. 1677149d518aSMauro Carvalho Chehab */ 1678d9b6f08aSMauro Carvalho Chehab if (pre_ber_layers) { 1679149d518aSMauro Carvalho Chehab /* 1680149d518aSMauro Carvalho Chehab * At least one per-layer BER measure was read. We can now 1681149d518aSMauro Carvalho Chehab * calculate the total BER 1682149d518aSMauro Carvalho Chehab * 1683149d518aSMauro Carvalho Chehab * Total Bit Error/Count is calculated as the sum of the 1684149d518aSMauro Carvalho Chehab * bit errors on all active layers. 1685149d518aSMauro Carvalho Chehab */ 1686149d518aSMauro Carvalho Chehab c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; 1687149d518aSMauro Carvalho Chehab c->pre_bit_error.stat[0].uvalue = t_pre_bit_error; 1688149d518aSMauro Carvalho Chehab c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; 1689149d518aSMauro Carvalho Chehab c->pre_bit_count.stat[0].uvalue = t_pre_bit_count; 1690f67102c4SMauro Carvalho Chehab } else { 1691f67102c4SMauro Carvalho Chehab c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 1692f67102c4SMauro Carvalho Chehab c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; 1693149d518aSMauro Carvalho Chehab } 1694149d518aSMauro Carvalho Chehab 1695d9b6f08aSMauro Carvalho Chehab /* 1696d9b6f08aSMauro Carvalho Chehab * Start showing global count if at least one error count is 1697d9b6f08aSMauro Carvalho Chehab * available. 1698d9b6f08aSMauro Carvalho Chehab */ 1699d9b6f08aSMauro Carvalho Chehab if (post_ber_layers) { 1700d9b6f08aSMauro Carvalho Chehab /* 1701d9b6f08aSMauro Carvalho Chehab * At least one per-layer BER measure was read. We can now 1702d9b6f08aSMauro Carvalho Chehab * calculate the total BER 1703d9b6f08aSMauro Carvalho Chehab * 1704d9b6f08aSMauro Carvalho Chehab * Total Bit Error/Count is calculated as the sum of the 1705d9b6f08aSMauro Carvalho Chehab * bit errors on all active layers. 1706d9b6f08aSMauro Carvalho Chehab */ 1707d9b6f08aSMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; 1708d9b6f08aSMauro Carvalho Chehab c->post_bit_error.stat[0].uvalue = t_post_bit_error; 1709d9b6f08aSMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; 1710d9b6f08aSMauro Carvalho Chehab c->post_bit_count.stat[0].uvalue = t_post_bit_count; 1711f67102c4SMauro Carvalho Chehab } else { 1712f67102c4SMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 1713f67102c4SMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; 1714d9b6f08aSMauro Carvalho Chehab } 1715d9b6f08aSMauro Carvalho Chehab 1716593ae89aSMauro Carvalho Chehab if (per_layers) { 1717593ae89aSMauro Carvalho Chehab /* 1718593ae89aSMauro Carvalho Chehab * At least one per-layer UCB measure was read. We can now 1719593ae89aSMauro Carvalho Chehab * calculate the total UCB 1720593ae89aSMauro Carvalho Chehab * 1721593ae89aSMauro Carvalho Chehab * Total block Error/Count is calculated as the sum of the 1722593ae89aSMauro Carvalho Chehab * block errors on all active layers. 1723593ae89aSMauro Carvalho Chehab */ 1724593ae89aSMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_COUNTER; 1725593ae89aSMauro Carvalho Chehab c->block_error.stat[0].uvalue = t_block_error; 1726593ae89aSMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_COUNTER; 1727593ae89aSMauro Carvalho Chehab c->block_count.stat[0].uvalue = t_block_count; 1728f67102c4SMauro Carvalho Chehab } else { 1729f67102c4SMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 1730f67102c4SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_COUNTER; 1731593ae89aSMauro Carvalho Chehab } 1732593ae89aSMauro Carvalho Chehab 1733149d518aSMauro Carvalho Chehab return rc; 1734149d518aSMauro Carvalho Chehab } 173509b6d21eSMauro Carvalho Chehab 173609b6d21eSMauro Carvalho Chehab /* 173709b6d21eSMauro Carvalho Chehab * The functions below are called via DVB callbacks, so they need to 173809b6d21eSMauro Carvalho Chehab * properly use the I2C gate control 173909b6d21eSMauro Carvalho Chehab */ 174009b6d21eSMauro Carvalho Chehab 1741dd4493efSMauro Carvalho Chehab static int mb86a20s_initfe(struct dvb_frontend *fe) 1742dd4493efSMauro Carvalho Chehab { 1743dd4493efSMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 1744768e6dadSMauro Carvalho Chehab u64 pll; 17450e4bbeddSMauro Carvalho Chehab u32 fclk; 1746dd4493efSMauro Carvalho Chehab int rc; 174704fa725eSMauro Carvalho Chehab u8 regD5 = 1, reg71, reg09 = 0x3a; 1748dd4493efSMauro Carvalho Chehab 1749f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 1750dd4493efSMauro Carvalho Chehab 1751dd4493efSMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) 1752dd4493efSMauro Carvalho Chehab fe->ops.i2c_gate_ctrl(fe, 0); 1753dd4493efSMauro Carvalho Chehab 1754dd4493efSMauro Carvalho Chehab /* Initialize the frontend */ 1755768e6dadSMauro Carvalho Chehab rc = mb86a20s_writeregdata(state, mb86a20s_init1); 1756dd4493efSMauro Carvalho Chehab if (rc < 0) 1757dd4493efSMauro Carvalho Chehab goto err; 1758dd4493efSMauro Carvalho Chehab 175904fa725eSMauro Carvalho Chehab if (!state->inversion) 176004fa725eSMauro Carvalho Chehab reg09 |= 0x04; 176104fa725eSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x09, reg09); 176204fa725eSMauro Carvalho Chehab if (rc < 0) 176304fa725eSMauro Carvalho Chehab goto err; 176404fa725eSMauro Carvalho Chehab if (!state->bw) 176504fa725eSMauro Carvalho Chehab reg71 = 1; 176604fa725eSMauro Carvalho Chehab else 176704fa725eSMauro Carvalho Chehab reg71 = 0; 176804fa725eSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x39, reg71); 176904fa725eSMauro Carvalho Chehab if (rc < 0) 177004fa725eSMauro Carvalho Chehab goto err; 177104fa725eSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x71, state->bw); 177204fa725eSMauro Carvalho Chehab if (rc < 0) 177304fa725eSMauro Carvalho Chehab goto err; 177404fa725eSMauro Carvalho Chehab if (state->subchannel) { 177504fa725eSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x44, state->subchannel); 177604fa725eSMauro Carvalho Chehab if (rc < 0) 177704fa725eSMauro Carvalho Chehab goto err; 177804fa725eSMauro Carvalho Chehab } 177904fa725eSMauro Carvalho Chehab 17800e4bbeddSMauro Carvalho Chehab fclk = state->config->fclk; 17810e4bbeddSMauro Carvalho Chehab if (!fclk) 17820e4bbeddSMauro Carvalho Chehab fclk = 32571428; 17830e4bbeddSMauro Carvalho Chehab 1784768e6dadSMauro Carvalho Chehab /* Adjust IF frequency to match tuner */ 1785768e6dadSMauro Carvalho Chehab if (fe->ops.tuner_ops.get_if_frequency) 1786768e6dadSMauro Carvalho Chehab fe->ops.tuner_ops.get_if_frequency(fe, &state->if_freq); 1787768e6dadSMauro Carvalho Chehab 1788768e6dadSMauro Carvalho Chehab if (!state->if_freq) 1789768e6dadSMauro Carvalho Chehab state->if_freq = 3300000; 1790768e6dadSMauro Carvalho Chehab 17910e4bbeddSMauro Carvalho Chehab pll = (((u64)1) << 34) * state->if_freq; 17920e4bbeddSMauro Carvalho Chehab do_div(pll, 63 * fclk); 17930e4bbeddSMauro Carvalho Chehab pll = (1 << 25) - pll; 17940e4bbeddSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x28, 0x2a); 17950e4bbeddSMauro Carvalho Chehab if (rc < 0) 17960e4bbeddSMauro Carvalho Chehab goto err; 17970e4bbeddSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x29, (pll >> 16) & 0xff); 17980e4bbeddSMauro Carvalho Chehab if (rc < 0) 17990e4bbeddSMauro Carvalho Chehab goto err; 18000e4bbeddSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x2a, (pll >> 8) & 0xff); 18010e4bbeddSMauro Carvalho Chehab if (rc < 0) 18020e4bbeddSMauro Carvalho Chehab goto err; 18030e4bbeddSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x2b, pll & 0xff); 18040e4bbeddSMauro Carvalho Chehab if (rc < 0) 18050e4bbeddSMauro Carvalho Chehab goto err; 18060e4bbeddSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s: fclk=%d, IF=%d, clock reg=0x%06llx\n", 18070e4bbeddSMauro Carvalho Chehab __func__, fclk, state->if_freq, (long long)pll); 18080e4bbeddSMauro Carvalho Chehab 1809768e6dadSMauro Carvalho Chehab /* pll = freq[Hz] * 2^24/10^6 / 16.285714286 */ 1810768e6dadSMauro Carvalho Chehab pll = state->if_freq * 1677721600L; 1811768e6dadSMauro Carvalho Chehab do_div(pll, 1628571429L); 1812768e6dadSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x28, 0x20); 1813768e6dadSMauro Carvalho Chehab if (rc < 0) 1814768e6dadSMauro Carvalho Chehab goto err; 1815768e6dadSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x29, (pll >> 16) & 0xff); 1816768e6dadSMauro Carvalho Chehab if (rc < 0) 1817768e6dadSMauro Carvalho Chehab goto err; 1818768e6dadSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x2a, (pll >> 8) & 0xff); 1819768e6dadSMauro Carvalho Chehab if (rc < 0) 1820768e6dadSMauro Carvalho Chehab goto err; 1821768e6dadSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x2b, pll & 0xff); 1822768e6dadSMauro Carvalho Chehab if (rc < 0) 1823768e6dadSMauro Carvalho Chehab goto err; 18240e4bbeddSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s: IF=%d, IF reg=0x%06llx\n", 1825768e6dadSMauro Carvalho Chehab __func__, state->if_freq, (long long)pll); 1826768e6dadSMauro Carvalho Chehab 18279d32069fSMauro Carvalho Chehab if (!state->config->is_serial) 1828dd4493efSMauro Carvalho Chehab regD5 &= ~1; 1829dd4493efSMauro Carvalho Chehab 1830dd4493efSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x50, 0xd5); 1831dd4493efSMauro Carvalho Chehab if (rc < 0) 1832dd4493efSMauro Carvalho Chehab goto err; 1833dd4493efSMauro Carvalho Chehab rc = mb86a20s_writereg(state, 0x51, regD5); 1834dd4493efSMauro Carvalho Chehab if (rc < 0) 1835dd4493efSMauro Carvalho Chehab goto err; 1836dd4493efSMauro Carvalho Chehab 1837768e6dadSMauro Carvalho Chehab rc = mb86a20s_writeregdata(state, mb86a20s_init2); 1838768e6dadSMauro Carvalho Chehab if (rc < 0) 1839768e6dadSMauro Carvalho Chehab goto err; 1840768e6dadSMauro Carvalho Chehab 1841768e6dadSMauro Carvalho Chehab 1842dd4493efSMauro Carvalho Chehab err: 1843dd4493efSMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) 1844dd4493efSMauro Carvalho Chehab fe->ops.i2c_gate_ctrl(fe, 1); 1845dd4493efSMauro Carvalho Chehab 1846dd4493efSMauro Carvalho Chehab if (rc < 0) { 1847dd4493efSMauro Carvalho Chehab state->need_init = true; 1848f66d81b5SMauro Carvalho Chehab dev_info(&state->i2c->dev, 1849f66d81b5SMauro Carvalho Chehab "mb86a20s: Init failed. Will try again later\n"); 1850dd4493efSMauro Carvalho Chehab } else { 1851dd4493efSMauro Carvalho Chehab state->need_init = false; 1852f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "Initialization succeeded.\n"); 1853dd4493efSMauro Carvalho Chehab } 1854dd4493efSMauro Carvalho Chehab return rc; 1855dd4493efSMauro Carvalho Chehab } 1856dd4493efSMauro Carvalho Chehab 1857dd4493efSMauro Carvalho Chehab static int mb86a20s_set_frontend(struct dvb_frontend *fe) 1858dd4493efSMauro Carvalho Chehab { 1859dd4493efSMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 1860dd4493efSMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 186104fa725eSMauro Carvalho Chehab int rc, if_freq; 1862f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 1863dd4493efSMauro Carvalho Chehab 186404fa725eSMauro Carvalho Chehab if (!c->isdbt_layer_enabled) 186504fa725eSMauro Carvalho Chehab c->isdbt_layer_enabled = 7; 186604fa725eSMauro Carvalho Chehab 186704fa725eSMauro Carvalho Chehab if (c->isdbt_layer_enabled == 1) 186804fa725eSMauro Carvalho Chehab state->bw = MB86A20S_1SEG; 186904fa725eSMauro Carvalho Chehab else if (c->isdbt_partial_reception) 187004fa725eSMauro Carvalho Chehab state->bw = MB86A20S_13SEG_PARTIAL; 187104fa725eSMauro Carvalho Chehab else 187204fa725eSMauro Carvalho Chehab state->bw = MB86A20S_13SEG; 187304fa725eSMauro Carvalho Chehab 187404fa725eSMauro Carvalho Chehab if (c->inversion == INVERSION_ON) 187504fa725eSMauro Carvalho Chehab state->inversion = true; 187604fa725eSMauro Carvalho Chehab else 187704fa725eSMauro Carvalho Chehab state->inversion = false; 187804fa725eSMauro Carvalho Chehab 187904fa725eSMauro Carvalho Chehab if (!c->isdbt_sb_mode) { 188004fa725eSMauro Carvalho Chehab state->subchannel = 0; 188104fa725eSMauro Carvalho Chehab } else { 188241c6e9ddSMauro Carvalho Chehab if (c->isdbt_sb_subchannel >= ARRAY_SIZE(mb86a20s_subchannel)) 188304fa725eSMauro Carvalho Chehab c->isdbt_sb_subchannel = 0; 188404fa725eSMauro Carvalho Chehab 188504fa725eSMauro Carvalho Chehab state->subchannel = mb86a20s_subchannel[c->isdbt_sb_subchannel]; 188604fa725eSMauro Carvalho Chehab } 188704fa725eSMauro Carvalho Chehab 1888dd4493efSMauro Carvalho Chehab /* 1889dd4493efSMauro Carvalho Chehab * Gate should already be opened, but it doesn't hurt to 1890dd4493efSMauro Carvalho Chehab * double-check 1891dd4493efSMauro Carvalho Chehab */ 1892dd4493efSMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) 1893dd4493efSMauro Carvalho Chehab fe->ops.i2c_gate_ctrl(fe, 1); 1894dd4493efSMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe); 1895dd4493efSMauro Carvalho Chehab 1896a78b41d5SMauro Carvalho Chehab if (fe->ops.tuner_ops.get_if_frequency) 1897768e6dadSMauro Carvalho Chehab fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); 1898768e6dadSMauro Carvalho Chehab 1899768e6dadSMauro Carvalho Chehab /* 1900dd4493efSMauro Carvalho Chehab * Make it more reliable: if, for some reason, the initial 1901dd4493efSMauro Carvalho Chehab * device initialization doesn't happen, initialize it when 1902dd4493efSMauro Carvalho Chehab * a SBTVD parameters are adjusted. 1903dd4493efSMauro Carvalho Chehab * 1904dd4493efSMauro Carvalho Chehab * Unfortunately, due to a hard to track bug at tda829x/tda18271, 1905dd4493efSMauro Carvalho Chehab * the agc callback logic is not called during DVB attach time, 1906dd4493efSMauro Carvalho Chehab * causing mb86a20s to not be initialized with Kworld SBTVD. 1907dd4493efSMauro Carvalho Chehab * So, this hack is needed, in order to make Kworld SBTVD to work. 1908768e6dadSMauro Carvalho Chehab * 1909768e6dadSMauro Carvalho Chehab * It is also needed to change the IF after the initial init. 1910a78b41d5SMauro Carvalho Chehab * 1911a78b41d5SMauro Carvalho Chehab * HACK: Always init the frontend when set_frontend is called: 1912a78b41d5SMauro Carvalho Chehab * it was noticed that, on some devices, it fails to lock on a 1913a78b41d5SMauro Carvalho Chehab * different channel. So, it is better to reset everything, even 1914a78b41d5SMauro Carvalho Chehab * wasting some time, than to loose channel lock. 1915dd4493efSMauro Carvalho Chehab */ 1916dd4493efSMauro Carvalho Chehab mb86a20s_initfe(fe); 1917dd4493efSMauro Carvalho Chehab 1918dd4493efSMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) 1919dd4493efSMauro Carvalho Chehab fe->ops.i2c_gate_ctrl(fe, 0); 1920d01a8ee3SMauro Carvalho Chehab 1921dd4493efSMauro Carvalho Chehab rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception); 192209b6d21eSMauro Carvalho Chehab mb86a20s_reset_counters(fe); 19233a2e4751SMauro Carvalho Chehab mb86a20s_stats_not_ready(fe); 1924d01a8ee3SMauro Carvalho Chehab 1925dd4493efSMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) 1926dd4493efSMauro Carvalho Chehab fe->ops.i2c_gate_ctrl(fe, 1); 1927dd4493efSMauro Carvalho Chehab 1928dd4493efSMauro Carvalho Chehab return rc; 1929dd4493efSMauro Carvalho Chehab } 1930dd4493efSMauro Carvalho Chehab 193109b6d21eSMauro Carvalho Chehab static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe, 19320df289a2SMauro Carvalho Chehab enum fe_status *status) 1933d36e418aSMauro Carvalho Chehab { 193409b6d21eSMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 193515b1c5a0SMauro Carvalho Chehab int rc, status_nr; 1936d36e418aSMauro Carvalho Chehab 193709b6d21eSMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 1938d36e418aSMauro Carvalho Chehab 1939d36e418aSMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) 1940d36e418aSMauro Carvalho Chehab fe->ops.i2c_gate_ctrl(fe, 0); 1941d36e418aSMauro Carvalho Chehab 194209b6d21eSMauro Carvalho Chehab /* Get lock */ 194315b1c5a0SMauro Carvalho Chehab status_nr = mb86a20s_read_status(fe, status); 194415b1c5a0SMauro Carvalho Chehab if (status_nr < 7) { 194509b6d21eSMauro Carvalho Chehab mb86a20s_stats_not_ready(fe); 194609b6d21eSMauro Carvalho Chehab mb86a20s_reset_frontend_cache(fe); 194709b6d21eSMauro Carvalho Chehab } 194815b1c5a0SMauro Carvalho Chehab if (status_nr < 0) { 1949149d518aSMauro Carvalho Chehab dev_err(&state->i2c->dev, 1950149d518aSMauro Carvalho Chehab "%s: Can't read frontend lock status\n", __func__); 195119157003SNicolas Iooss rc = status_nr; 195209b6d21eSMauro Carvalho Chehab goto error; 1953149d518aSMauro Carvalho Chehab } 195409b6d21eSMauro Carvalho Chehab 195509b6d21eSMauro Carvalho Chehab /* Get signal strength */ 195609b6d21eSMauro Carvalho Chehab rc = mb86a20s_read_signal_strength(fe); 195709b6d21eSMauro Carvalho Chehab if (rc < 0) { 1958149d518aSMauro Carvalho Chehab dev_err(&state->i2c->dev, 1959149d518aSMauro Carvalho Chehab "%s: Can't reset VBER registers.\n", __func__); 196009b6d21eSMauro Carvalho Chehab mb86a20s_stats_not_ready(fe); 196109b6d21eSMauro Carvalho Chehab mb86a20s_reset_frontend_cache(fe); 1962149d518aSMauro Carvalho Chehab 1963149d518aSMauro Carvalho Chehab rc = 0; /* Status is OK */ 196409b6d21eSMauro Carvalho Chehab goto error; 196509b6d21eSMauro Carvalho Chehab } 196609b6d21eSMauro Carvalho Chehab 196715b1c5a0SMauro Carvalho Chehab if (status_nr >= 7) { 196809b6d21eSMauro Carvalho Chehab /* Get TMCC info*/ 196909b6d21eSMauro Carvalho Chehab rc = mb86a20s_get_frontend(fe); 1970149d518aSMauro Carvalho Chehab if (rc < 0) { 1971149d518aSMauro Carvalho Chehab dev_err(&state->i2c->dev, 1972149d518aSMauro Carvalho Chehab "%s: Can't get FE TMCC data.\n", __func__); 1973149d518aSMauro Carvalho Chehab rc = 0; /* Status is OK */ 197409b6d21eSMauro Carvalho Chehab goto error; 197509b6d21eSMauro Carvalho Chehab } 197609b6d21eSMauro Carvalho Chehab 1977149d518aSMauro Carvalho Chehab /* Get statistics */ 197815b1c5a0SMauro Carvalho Chehab rc = mb86a20s_get_stats(fe, status_nr); 1979149d518aSMauro Carvalho Chehab if (rc < 0 && rc != -EBUSY) { 1980149d518aSMauro Carvalho Chehab dev_err(&state->i2c->dev, 1981149d518aSMauro Carvalho Chehab "%s: Can't get FE statistics.\n", __func__); 1982149d518aSMauro Carvalho Chehab rc = 0; 1983149d518aSMauro Carvalho Chehab goto error; 1984149d518aSMauro Carvalho Chehab } 1985149d518aSMauro Carvalho Chehab rc = 0; /* Don't return EBUSY to userspace */ 1986149d518aSMauro Carvalho Chehab } 1987149d518aSMauro Carvalho Chehab goto ok; 1988149d518aSMauro Carvalho Chehab 1989149d518aSMauro Carvalho Chehab error: 199009b6d21eSMauro Carvalho Chehab mb86a20s_stats_not_ready(fe); 1991d36e418aSMauro Carvalho Chehab 1992149d518aSMauro Carvalho Chehab ok: 1993d36e418aSMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) 1994d36e418aSMauro Carvalho Chehab fe->ops.i2c_gate_ctrl(fe, 1); 1995149d518aSMauro Carvalho Chehab 199609b6d21eSMauro Carvalho Chehab return rc; 1997d36e418aSMauro Carvalho Chehab } 1998d36e418aSMauro Carvalho Chehab 199909b6d21eSMauro Carvalho Chehab static int mb86a20s_read_signal_strength_from_cache(struct dvb_frontend *fe, 200009b6d21eSMauro Carvalho Chehab u16 *strength) 200109b6d21eSMauro Carvalho Chehab { 200209b6d21eSMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 200309b6d21eSMauro Carvalho Chehab 200409b6d21eSMauro Carvalho Chehab 200509b6d21eSMauro Carvalho Chehab *strength = c->strength.stat[0].uvalue; 200609b6d21eSMauro Carvalho Chehab 200709b6d21eSMauro Carvalho Chehab return 0; 200809b6d21eSMauro Carvalho Chehab } 200909b6d21eSMauro Carvalho Chehab 20109a0bf528SMauro Carvalho Chehab static int mb86a20s_tune(struct dvb_frontend *fe, 20119a0bf528SMauro Carvalho Chehab bool re_tune, 20129a0bf528SMauro Carvalho Chehab unsigned int mode_flags, 20139a0bf528SMauro Carvalho Chehab unsigned int *delay, 20140df289a2SMauro Carvalho Chehab enum fe_status *status) 20159a0bf528SMauro Carvalho Chehab { 2016f66d81b5SMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 20179a0bf528SMauro Carvalho Chehab int rc = 0; 20189a0bf528SMauro Carvalho Chehab 2019f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 20209a0bf528SMauro Carvalho Chehab 20219a0bf528SMauro Carvalho Chehab if (re_tune) 20229a0bf528SMauro Carvalho Chehab rc = mb86a20s_set_frontend(fe); 20239a0bf528SMauro Carvalho Chehab 20249a0bf528SMauro Carvalho Chehab if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) 202509b6d21eSMauro Carvalho Chehab mb86a20s_read_status_and_stats(fe, status); 20269a0bf528SMauro Carvalho Chehab 20279a0bf528SMauro Carvalho Chehab return rc; 20289a0bf528SMauro Carvalho Chehab } 20299a0bf528SMauro Carvalho Chehab 20309a0bf528SMauro Carvalho Chehab static void mb86a20s_release(struct dvb_frontend *fe) 20319a0bf528SMauro Carvalho Chehab { 20329a0bf528SMauro Carvalho Chehab struct mb86a20s_state *state = fe->demodulator_priv; 20339a0bf528SMauro Carvalho Chehab 2034f66d81b5SMauro Carvalho Chehab dev_dbg(&state->i2c->dev, "%s called.\n", __func__); 20359a0bf528SMauro Carvalho Chehab 20369a0bf528SMauro Carvalho Chehab kfree(state); 20379a0bf528SMauro Carvalho Chehab } 20389a0bf528SMauro Carvalho Chehab 20398d718e53SLuc Van Oostenryck static enum dvbfe_algo mb86a20s_get_frontend_algo(struct dvb_frontend *fe) 2040dafb65fbSMauro Carvalho Chehab { 2041dafb65fbSMauro Carvalho Chehab return DVBFE_ALGO_HW; 2042dafb65fbSMauro Carvalho Chehab } 2043dafb65fbSMauro Carvalho Chehab 2044bd336e63SMax Kellermann static const struct dvb_frontend_ops mb86a20s_ops; 20459a0bf528SMauro Carvalho Chehab 20469a0bf528SMauro Carvalho Chehab struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, 20479a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c) 20489a0bf528SMauro Carvalho Chehab { 2049f66d81b5SMauro Carvalho Chehab struct mb86a20s_state *state; 20509a0bf528SMauro Carvalho Chehab u8 rev; 20519a0bf528SMauro Carvalho Chehab 2052f167e302SMauro Carvalho Chehab dev_dbg(&i2c->dev, "%s called.\n", __func__); 2053f167e302SMauro Carvalho Chehab 20549a0bf528SMauro Carvalho Chehab /* allocate memory for the internal state */ 20552d3da59fSMarkus Elfring state = kzalloc(sizeof(*state), GFP_KERNEL); 2056c38e8657SMarkus Elfring if (!state) 20579722e569SMarkus Elfring return NULL; 20589a0bf528SMauro Carvalho Chehab 20599a0bf528SMauro Carvalho Chehab /* setup the state */ 20609a0bf528SMauro Carvalho Chehab state->config = config; 20619a0bf528SMauro Carvalho Chehab state->i2c = i2c; 20629a0bf528SMauro Carvalho Chehab 20639a0bf528SMauro Carvalho Chehab /* create dvb_frontend */ 20649a0bf528SMauro Carvalho Chehab memcpy(&state->frontend.ops, &mb86a20s_ops, 20659a0bf528SMauro Carvalho Chehab sizeof(struct dvb_frontend_ops)); 20669a0bf528SMauro Carvalho Chehab state->frontend.demodulator_priv = state; 20679a0bf528SMauro Carvalho Chehab 20689a0bf528SMauro Carvalho Chehab /* Check if it is a mb86a20s frontend */ 20699a0bf528SMauro Carvalho Chehab rev = mb86a20s_readreg(state, 0); 20709722e569SMarkus Elfring if (rev != 0x13) { 20719722e569SMarkus Elfring kfree(state); 2072f167e302SMauro Carvalho Chehab dev_dbg(&i2c->dev, 2073f66d81b5SMauro Carvalho Chehab "Frontend revision %d is unknown - aborting.\n", 20749a0bf528SMauro Carvalho Chehab rev); 20759722e569SMarkus Elfring return NULL; 20769a0bf528SMauro Carvalho Chehab } 20779a0bf528SMauro Carvalho Chehab 20789722e569SMarkus Elfring dev_info(&i2c->dev, "Detected a Fujitsu mb86a20s frontend\n"); 20799a0bf528SMauro Carvalho Chehab return &state->frontend; 20809a0bf528SMauro Carvalho Chehab } 20819a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(mb86a20s_attach); 20829a0bf528SMauro Carvalho Chehab 2083bd336e63SMax Kellermann static const struct dvb_frontend_ops mb86a20s_ops = { 20849a0bf528SMauro Carvalho Chehab .delsys = { SYS_ISDBT }, 20859a0bf528SMauro Carvalho Chehab /* Use dib8000 values per default */ 20869a0bf528SMauro Carvalho Chehab .info = { 20879a0bf528SMauro Carvalho Chehab .name = "Fujitsu mb86A20s", 208804fa725eSMauro Carvalho Chehab .caps = FE_CAN_RECOVER | 20899a0bf528SMauro Carvalho Chehab FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 20909a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 20919a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | 20929a0bf528SMauro Carvalho Chehab FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_QAM_AUTO | 20939a0bf528SMauro Carvalho Chehab FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, 20949a0bf528SMauro Carvalho Chehab /* Actually, those values depend on the used tuner */ 2095f1b1eabfSMauro Carvalho Chehab .frequency_min_hz = 45 * MHz, 2096f1b1eabfSMauro Carvalho Chehab .frequency_max_hz = 864 * MHz, 2097f1b1eabfSMauro Carvalho Chehab .frequency_stepsize_hz = 62500, 20989a0bf528SMauro Carvalho Chehab }, 20999a0bf528SMauro Carvalho Chehab 21009a0bf528SMauro Carvalho Chehab .release = mb86a20s_release, 21019a0bf528SMauro Carvalho Chehab 21029a0bf528SMauro Carvalho Chehab .init = mb86a20s_initfe, 21039a0bf528SMauro Carvalho Chehab .set_frontend = mb86a20s_set_frontend, 210409b6d21eSMauro Carvalho Chehab .read_status = mb86a20s_read_status_and_stats, 210509b6d21eSMauro Carvalho Chehab .read_signal_strength = mb86a20s_read_signal_strength_from_cache, 21069a0bf528SMauro Carvalho Chehab .tune = mb86a20s_tune, 2107dafb65fbSMauro Carvalho Chehab .get_frontend_algo = mb86a20s_get_frontend_algo, 21089a0bf528SMauro Carvalho Chehab }; 21099a0bf528SMauro Carvalho Chehab 21109a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware"); 211137e59f87SMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab"); 21129a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 2113