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