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