18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * i2c tv tuner chip device driver
48c2ecf20Sopenharmony_ci * controls all those simple 4-control-bytes style tuners.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This "tuner-simple" module was split apart from the original "tuner" module.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/delay.h>
98c2ecf20Sopenharmony_ci#include <linux/i2c.h>
108c2ecf20Sopenharmony_ci#include <linux/videodev2.h>
118c2ecf20Sopenharmony_ci#include <media/tuner.h>
128c2ecf20Sopenharmony_ci#include <media/v4l2-common.h>
138c2ecf20Sopenharmony_ci#include <media/tuner-types.h>
148c2ecf20Sopenharmony_ci#include "tuner-i2c.h"
158c2ecf20Sopenharmony_ci#include "tuner-simple.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic int debug;
188c2ecf20Sopenharmony_cimodule_param(debug, int, 0644);
198c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "enable verbose debug messages");
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define TUNER_SIMPLE_MAX 64
228c2ecf20Sopenharmony_cistatic unsigned int simple_devcount;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic int offset;
258c2ecf20Sopenharmony_cimodule_param(offset, int, 0664);
268c2ecf20Sopenharmony_ciMODULE_PARM_DESC(offset, "Allows to specify an offset for tuner");
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic unsigned int atv_input[TUNER_SIMPLE_MAX] = \
298c2ecf20Sopenharmony_ci			{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
308c2ecf20Sopenharmony_cistatic unsigned int dtv_input[TUNER_SIMPLE_MAX] = \
318c2ecf20Sopenharmony_ci			{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
328c2ecf20Sopenharmony_cimodule_param_array(atv_input, int, NULL, 0644);
338c2ecf20Sopenharmony_cimodule_param_array(dtv_input, int, NULL, 0644);
348c2ecf20Sopenharmony_ciMODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect");
358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect");
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------- */
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* tv standard selection for Temic 4046 FM5
408c2ecf20Sopenharmony_ci   this value takes the low bits of control byte 2
418c2ecf20Sopenharmony_ci   from datasheet Rev.01, Feb.00
428c2ecf20Sopenharmony_ci     standard     BG      I       L       L2      D
438c2ecf20Sopenharmony_ci     picture IF   38.9    38.9    38.9    33.95   38.9
448c2ecf20Sopenharmony_ci     sound 1      33.4    32.9    32.4    40.45   32.4
458c2ecf20Sopenharmony_ci     sound 2      33.16
468c2ecf20Sopenharmony_ci     NICAM        33.05   32.348  33.05           33.05
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_ci#define TEMIC_SET_PAL_I         0x05
498c2ecf20Sopenharmony_ci#define TEMIC_SET_PAL_DK        0x09
508c2ecf20Sopenharmony_ci#define TEMIC_SET_PAL_L         0x0a /* SECAM ? */
518c2ecf20Sopenharmony_ci#define TEMIC_SET_PAL_L2        0x0b /* change IF ! */
528c2ecf20Sopenharmony_ci#define TEMIC_SET_PAL_BG        0x0c
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/* tv tuner system standard selection for Philips FQ1216ME
558c2ecf20Sopenharmony_ci   this value takes the low bits of control byte 2
568c2ecf20Sopenharmony_ci   from datasheet "1999 Nov 16" (supersedes "1999 Mar 23")
578c2ecf20Sopenharmony_ci     standard		BG	DK	I	L	L`
588c2ecf20Sopenharmony_ci     picture carrier	38.90	38.90	38.90	38.90	33.95
598c2ecf20Sopenharmony_ci     colour		34.47	34.47	34.47	34.47	38.38
608c2ecf20Sopenharmony_ci     sound 1		33.40	32.40	32.90	32.40	40.45
618c2ecf20Sopenharmony_ci     sound 2		33.16	-	-	-	-
628c2ecf20Sopenharmony_ci     NICAM		33.05	33.05	32.35	33.05	39.80
638c2ecf20Sopenharmony_ci */
648c2ecf20Sopenharmony_ci#define PHILIPS_SET_PAL_I	0x01 /* Bit 2 always zero !*/
658c2ecf20Sopenharmony_ci#define PHILIPS_SET_PAL_BGDK	0x09
668c2ecf20Sopenharmony_ci#define PHILIPS_SET_PAL_L2	0x0a
678c2ecf20Sopenharmony_ci#define PHILIPS_SET_PAL_L	0x0b
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/* system switching for Philips FI1216MF MK2
708c2ecf20Sopenharmony_ci   from datasheet "1996 Jul 09",
718c2ecf20Sopenharmony_ci    standard         BG     L      L'
728c2ecf20Sopenharmony_ci    picture carrier  38.90  38.90  33.95
738c2ecf20Sopenharmony_ci    colour	     34.47  34.37  38.38
748c2ecf20Sopenharmony_ci    sound 1          33.40  32.40  40.45
758c2ecf20Sopenharmony_ci    sound 2          33.16  -      -
768c2ecf20Sopenharmony_ci    NICAM            33.05  33.05  39.80
778c2ecf20Sopenharmony_ci */
788c2ecf20Sopenharmony_ci#define PHILIPS_MF_SET_STD_BG	0x01 /* Bit 2 must be zero, Bit 3 is system output */
798c2ecf20Sopenharmony_ci#define PHILIPS_MF_SET_STD_L	0x03 /* Used on Secam France */
808c2ecf20Sopenharmony_ci#define PHILIPS_MF_SET_STD_LC	0x02 /* Used on SECAM L' */
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci/* Control byte */
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci#define TUNER_RATIO_MASK        0x06 /* Bit cb1:cb2 */
858c2ecf20Sopenharmony_ci#define TUNER_RATIO_SELECT_50   0x00
868c2ecf20Sopenharmony_ci#define TUNER_RATIO_SELECT_32   0x02
878c2ecf20Sopenharmony_ci#define TUNER_RATIO_SELECT_166  0x04
888c2ecf20Sopenharmony_ci#define TUNER_RATIO_SELECT_62   0x06
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci#define TUNER_CHARGE_PUMP       0x40  /* Bit cb6 */
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/* Status byte */
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci#define TUNER_POR	  0x80
958c2ecf20Sopenharmony_ci#define TUNER_FL          0x40
968c2ecf20Sopenharmony_ci#define TUNER_MODE        0x38
978c2ecf20Sopenharmony_ci#define TUNER_AFC         0x07
988c2ecf20Sopenharmony_ci#define TUNER_SIGNAL      0x07
998c2ecf20Sopenharmony_ci#define TUNER_STEREO      0x10
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci#define TUNER_PLL_LOCKED   0x40
1028c2ecf20Sopenharmony_ci#define TUNER_STEREO_MK3   0x04
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(tuner_simple_list_mutex);
1058c2ecf20Sopenharmony_cistatic LIST_HEAD(hybrid_tuner_instance_list);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistruct tuner_simple_priv {
1088c2ecf20Sopenharmony_ci	unsigned int nr;
1098c2ecf20Sopenharmony_ci	u16 last_div;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	struct tuner_i2c_props i2c_props;
1128c2ecf20Sopenharmony_ci	struct list_head hybrid_tuner_instance_list;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	unsigned int type;
1158c2ecf20Sopenharmony_ci	struct tunertype *tun;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	u32 frequency;
1188c2ecf20Sopenharmony_ci	u32 bandwidth;
1198c2ecf20Sopenharmony_ci	bool radio_mode;
1208c2ecf20Sopenharmony_ci};
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------- */
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic int tuner_read_status(struct dvb_frontend *fe)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
1278c2ecf20Sopenharmony_ci	unsigned char byte;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1))
1308c2ecf20Sopenharmony_ci		return 0;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	return byte;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic inline int tuner_signal(const int status)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	return (status & TUNER_SIGNAL) << 13;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic inline int tuner_stereo(const int type, const int status)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	switch (type) {
1438c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FM1216ME_MK3:
1448c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FM1236_MK3:
1458c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FM1256_IH3:
1468c2ecf20Sopenharmony_ci	case TUNER_LG_NTSC_TAPE:
1478c2ecf20Sopenharmony_ci	case TUNER_TCL_MF02GIP_5N:
1488c2ecf20Sopenharmony_ci		return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
1498c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FM1216MK5:
1508c2ecf20Sopenharmony_ci		return status | TUNER_STEREO;
1518c2ecf20Sopenharmony_ci	default:
1528c2ecf20Sopenharmony_ci		return status & TUNER_STEREO;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic inline int tuner_islocked(const int status)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	return (status & TUNER_FL);
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic inline int tuner_afcstatus(const int status)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	return (status & TUNER_AFC) - 2;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic int simple_get_status(struct dvb_frontend *fe, u32 *status)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
1708c2ecf20Sopenharmony_ci	int tuner_status;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	if (priv->i2c_props.adap == NULL)
1738c2ecf20Sopenharmony_ci		return -EINVAL;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	tuner_status = tuner_read_status(fe);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	*status = 0;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (tuner_islocked(tuner_status))
1808c2ecf20Sopenharmony_ci		*status = TUNER_STATUS_LOCKED;
1818c2ecf20Sopenharmony_ci	if (tuner_stereo(priv->type, tuner_status))
1828c2ecf20Sopenharmony_ci		*status |= TUNER_STATUS_STEREO;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status));
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	return 0;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
1928c2ecf20Sopenharmony_ci	int signal;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (priv->i2c_props.adap == NULL || !priv->radio_mode)
1958c2ecf20Sopenharmony_ci		return -EINVAL;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	signal = tuner_signal(tuner_read_status(fe));
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	*strength = signal;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	tuner_dbg("Signal strength: %d\n", signal);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	return 0;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------- */
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic inline char *tuner_param_name(enum param_type type)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	char *name;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	switch (type) {
2138c2ecf20Sopenharmony_ci	case TUNER_PARAM_TYPE_RADIO:
2148c2ecf20Sopenharmony_ci		name = "radio";
2158c2ecf20Sopenharmony_ci		break;
2168c2ecf20Sopenharmony_ci	case TUNER_PARAM_TYPE_PAL:
2178c2ecf20Sopenharmony_ci		name = "pal";
2188c2ecf20Sopenharmony_ci		break;
2198c2ecf20Sopenharmony_ci	case TUNER_PARAM_TYPE_SECAM:
2208c2ecf20Sopenharmony_ci		name = "secam";
2218c2ecf20Sopenharmony_ci		break;
2228c2ecf20Sopenharmony_ci	case TUNER_PARAM_TYPE_NTSC:
2238c2ecf20Sopenharmony_ci		name = "ntsc";
2248c2ecf20Sopenharmony_ci		break;
2258c2ecf20Sopenharmony_ci	case TUNER_PARAM_TYPE_DIGITAL:
2268c2ecf20Sopenharmony_ci		name = "digital";
2278c2ecf20Sopenharmony_ci		break;
2288c2ecf20Sopenharmony_ci	default:
2298c2ecf20Sopenharmony_ci		name = "unknown";
2308c2ecf20Sopenharmony_ci		break;
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci	return name;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic struct tuner_params *simple_tuner_params(struct dvb_frontend *fe,
2368c2ecf20Sopenharmony_ci						enum param_type desired_type)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
2398c2ecf20Sopenharmony_ci	struct tunertype *tun = priv->tun;
2408c2ecf20Sopenharmony_ci	int i;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	for (i = 0; i < tun->count; i++)
2438c2ecf20Sopenharmony_ci		if (desired_type == tun->params[i].type)
2448c2ecf20Sopenharmony_ci			break;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	/* use default tuner params if desired_type not available */
2478c2ecf20Sopenharmony_ci	if (i == tun->count) {
2488c2ecf20Sopenharmony_ci		tuner_dbg("desired params (%s) undefined for tuner %d\n",
2498c2ecf20Sopenharmony_ci			  tuner_param_name(desired_type), priv->type);
2508c2ecf20Sopenharmony_ci		i = 0;
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	tuner_dbg("using tuner params #%d (%s)\n", i,
2548c2ecf20Sopenharmony_ci		  tuner_param_name(tun->params[i].type));
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	return &tun->params[i];
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic int simple_config_lookup(struct dvb_frontend *fe,
2608c2ecf20Sopenharmony_ci				struct tuner_params *t_params,
2618c2ecf20Sopenharmony_ci				unsigned *frequency, u8 *config, u8 *cb)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
2648c2ecf20Sopenharmony_ci	int i;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	for (i = 0; i < t_params->count; i++) {
2678c2ecf20Sopenharmony_ci		if (*frequency > t_params->ranges[i].limit)
2688c2ecf20Sopenharmony_ci			continue;
2698c2ecf20Sopenharmony_ci		break;
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci	if (i == t_params->count) {
2728c2ecf20Sopenharmony_ci		tuner_dbg("frequency out of range (%d > %d)\n",
2738c2ecf20Sopenharmony_ci			  *frequency, t_params->ranges[i - 1].limit);
2748c2ecf20Sopenharmony_ci		*frequency = t_params->ranges[--i].limit;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci	*config = t_params->ranges[i].config;
2778c2ecf20Sopenharmony_ci	*cb     = t_params->ranges[i].cb;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	tuner_dbg("freq = %d.%02d (%d), range = %d, config = 0x%02x, cb = 0x%02x\n",
2808c2ecf20Sopenharmony_ci		  *frequency / 16, *frequency % 16 * 100 / 16, *frequency,
2818c2ecf20Sopenharmony_ci		  i, *config, *cb);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	return i;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------- */
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic void simple_set_rf_input(struct dvb_frontend *fe,
2898c2ecf20Sopenharmony_ci				u8 *config, u8 *cb, unsigned int rf)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	switch (priv->type) {
2948c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_TUV1236D:
2958c2ecf20Sopenharmony_ci		switch (rf) {
2968c2ecf20Sopenharmony_ci		case 1:
2978c2ecf20Sopenharmony_ci			*cb |= 0x08;
2988c2ecf20Sopenharmony_ci			break;
2998c2ecf20Sopenharmony_ci		default:
3008c2ecf20Sopenharmony_ci			*cb &= ~0x08;
3018c2ecf20Sopenharmony_ci			break;
3028c2ecf20Sopenharmony_ci		}
3038c2ecf20Sopenharmony_ci		break;
3048c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FCV1236D:
3058c2ecf20Sopenharmony_ci		switch (rf) {
3068c2ecf20Sopenharmony_ci		case 1:
3078c2ecf20Sopenharmony_ci			*cb |= 0x01;
3088c2ecf20Sopenharmony_ci			break;
3098c2ecf20Sopenharmony_ci		default:
3108c2ecf20Sopenharmony_ci			*cb &= ~0x01;
3118c2ecf20Sopenharmony_ci			break;
3128c2ecf20Sopenharmony_ci		}
3138c2ecf20Sopenharmony_ci		break;
3148c2ecf20Sopenharmony_ci	default:
3158c2ecf20Sopenharmony_ci		break;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic int simple_std_setup(struct dvb_frontend *fe,
3208c2ecf20Sopenharmony_ci			    struct analog_parameters *params,
3218c2ecf20Sopenharmony_ci			    u8 *config, u8 *cb)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
3248c2ecf20Sopenharmony_ci	int rc;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	/* tv norm specific stuff for multi-norm tuners */
3278c2ecf20Sopenharmony_ci	switch (priv->type) {
3288c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_SECAM: /* FI1216MF */
3298c2ecf20Sopenharmony_ci		/* 0x01 -> ??? no change ??? */
3308c2ecf20Sopenharmony_ci		/* 0x02 -> PAL BDGHI / SECAM L */
3318c2ecf20Sopenharmony_ci		/* 0x04 -> ??? PAL others / SECAM others ??? */
3328c2ecf20Sopenharmony_ci		*cb &= ~0x03;
3338c2ecf20Sopenharmony_ci		if (params->std & V4L2_STD_SECAM_L)
3348c2ecf20Sopenharmony_ci			/* also valid for V4L2_STD_SECAM */
3358c2ecf20Sopenharmony_ci			*cb |= PHILIPS_MF_SET_STD_L;
3368c2ecf20Sopenharmony_ci		else if (params->std & V4L2_STD_SECAM_LC)
3378c2ecf20Sopenharmony_ci			*cb |= PHILIPS_MF_SET_STD_LC;
3388c2ecf20Sopenharmony_ci		else /* V4L2_STD_B|V4L2_STD_GH */
3398c2ecf20Sopenharmony_ci			*cb |= PHILIPS_MF_SET_STD_BG;
3408c2ecf20Sopenharmony_ci		break;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	case TUNER_TEMIC_4046FM5:
3438c2ecf20Sopenharmony_ci		*cb &= ~0x0f;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		if (params->std & V4L2_STD_PAL_BG) {
3468c2ecf20Sopenharmony_ci			*cb |= TEMIC_SET_PAL_BG;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		} else if (params->std & V4L2_STD_PAL_I) {
3498c2ecf20Sopenharmony_ci			*cb |= TEMIC_SET_PAL_I;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci		} else if (params->std & V4L2_STD_PAL_DK) {
3528c2ecf20Sopenharmony_ci			*cb |= TEMIC_SET_PAL_DK;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci		} else if (params->std & V4L2_STD_SECAM_L) {
3558c2ecf20Sopenharmony_ci			*cb |= TEMIC_SET_PAL_L;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci		}
3588c2ecf20Sopenharmony_ci		break;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FQ1216ME:
3618c2ecf20Sopenharmony_ci		*cb &= ~0x0f;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci		if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
3648c2ecf20Sopenharmony_ci			*cb |= PHILIPS_SET_PAL_BGDK;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci		} else if (params->std & V4L2_STD_PAL_I) {
3678c2ecf20Sopenharmony_ci			*cb |= PHILIPS_SET_PAL_I;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci		} else if (params->std & V4L2_STD_SECAM_L) {
3708c2ecf20Sopenharmony_ci			*cb |= PHILIPS_SET_PAL_L;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci		}
3738c2ecf20Sopenharmony_ci		break;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FCV1236D:
3768c2ecf20Sopenharmony_ci		/* 0x00 -> ATSC antenna input 1 */
3778c2ecf20Sopenharmony_ci		/* 0x01 -> ATSC antenna input 2 */
3788c2ecf20Sopenharmony_ci		/* 0x02 -> NTSC antenna input 1 */
3798c2ecf20Sopenharmony_ci		/* 0x03 -> NTSC antenna input 2 */
3808c2ecf20Sopenharmony_ci		*cb &= ~0x03;
3818c2ecf20Sopenharmony_ci		if (!(params->std & V4L2_STD_ATSC))
3828c2ecf20Sopenharmony_ci			*cb |= 2;
3838c2ecf20Sopenharmony_ci		break;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	case TUNER_MICROTUNE_4042FI5:
3868c2ecf20Sopenharmony_ci		/* Set the charge pump for fast tuning */
3878c2ecf20Sopenharmony_ci		*config |= TUNER_CHARGE_PUMP;
3888c2ecf20Sopenharmony_ci		break;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_TUV1236D:
3918c2ecf20Sopenharmony_ci	{
3928c2ecf20Sopenharmony_ci		struct tuner_i2c_props i2c = priv->i2c_props;
3938c2ecf20Sopenharmony_ci		/* 0x40 -> ATSC antenna input 1 */
3948c2ecf20Sopenharmony_ci		/* 0x48 -> ATSC antenna input 2 */
3958c2ecf20Sopenharmony_ci		/* 0x00 -> NTSC antenna input 1 */
3968c2ecf20Sopenharmony_ci		/* 0x08 -> NTSC antenna input 2 */
3978c2ecf20Sopenharmony_ci		u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00};
3988c2ecf20Sopenharmony_ci		*cb &= ~0x40;
3998c2ecf20Sopenharmony_ci		if (params->std & V4L2_STD_ATSC) {
4008c2ecf20Sopenharmony_ci			*cb |= 0x40;
4018c2ecf20Sopenharmony_ci			buffer[1] = 0x04;
4028c2ecf20Sopenharmony_ci		}
4038c2ecf20Sopenharmony_ci		/* set to the correct mode (analog or digital) */
4048c2ecf20Sopenharmony_ci		i2c.addr = 0x0a;
4058c2ecf20Sopenharmony_ci		rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2);
4068c2ecf20Sopenharmony_ci		if (2 != rc)
4078c2ecf20Sopenharmony_ci			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",
4088c2ecf20Sopenharmony_ci				   rc);
4098c2ecf20Sopenharmony_ci		rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2);
4108c2ecf20Sopenharmony_ci		if (2 != rc)
4118c2ecf20Sopenharmony_ci			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",
4128c2ecf20Sopenharmony_ci				   rc);
4138c2ecf20Sopenharmony_ci		break;
4148c2ecf20Sopenharmony_ci	}
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci	if (atv_input[priv->nr])
4178c2ecf20Sopenharmony_ci		simple_set_rf_input(fe, config, cb, atv_input[priv->nr]);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	return 0;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
4258c2ecf20Sopenharmony_ci	int rc;
4268c2ecf20Sopenharmony_ci	u8 buffer[2];
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	buffer[0] = (config & ~0x38) | 0x18;
4298c2ecf20Sopenharmony_ci	buffer[1] = aux;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
4348c2ecf20Sopenharmony_ci	if (2 != rc)
4358c2ecf20Sopenharmony_ci		tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	return rc == 2 ? 0 : rc;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
4418c2ecf20Sopenharmony_ci			    u16 div, u8 config, u8 cb)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
4448c2ecf20Sopenharmony_ci	int rc;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	switch (priv->type) {
4478c2ecf20Sopenharmony_ci	case TUNER_LG_TDVS_H06XF:
4488c2ecf20Sopenharmony_ci		simple_set_aux_byte(fe, config, 0x20);
4498c2ecf20Sopenharmony_ci		break;
4508c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FQ1216LME_MK3:
4518c2ecf20Sopenharmony_ci		simple_set_aux_byte(fe, config, 0x60); /* External AGC */
4528c2ecf20Sopenharmony_ci		break;
4538c2ecf20Sopenharmony_ci	case TUNER_MICROTUNE_4042FI5:
4548c2ecf20Sopenharmony_ci	{
4558c2ecf20Sopenharmony_ci		/* FIXME - this may also work for other tuners */
4568c2ecf20Sopenharmony_ci		unsigned long timeout = jiffies + msecs_to_jiffies(1);
4578c2ecf20Sopenharmony_ci		u8 status_byte = 0;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci		/* Wait until the PLL locks */
4608c2ecf20Sopenharmony_ci		for (;;) {
4618c2ecf20Sopenharmony_ci			if (time_after(jiffies, timeout))
4628c2ecf20Sopenharmony_ci				return 0;
4638c2ecf20Sopenharmony_ci			rc = tuner_i2c_xfer_recv(&priv->i2c_props,
4648c2ecf20Sopenharmony_ci						 &status_byte, 1);
4658c2ecf20Sopenharmony_ci			if (1 != rc) {
4668c2ecf20Sopenharmony_ci				tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",
4678c2ecf20Sopenharmony_ci					   rc);
4688c2ecf20Sopenharmony_ci				break;
4698c2ecf20Sopenharmony_ci			}
4708c2ecf20Sopenharmony_ci			if (status_byte & TUNER_PLL_LOCKED)
4718c2ecf20Sopenharmony_ci				break;
4728c2ecf20Sopenharmony_ci			udelay(10);
4738c2ecf20Sopenharmony_ci		}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci		/* Set the charge pump for optimized phase noise figure */
4768c2ecf20Sopenharmony_ci		config &= ~TUNER_CHARGE_PUMP;
4778c2ecf20Sopenharmony_ci		buffer[0] = (div>>8) & 0x7f;
4788c2ecf20Sopenharmony_ci		buffer[1] = div      & 0xff;
4798c2ecf20Sopenharmony_ci		buffer[2] = config;
4808c2ecf20Sopenharmony_ci		buffer[3] = cb;
4818c2ecf20Sopenharmony_ci		tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
4828c2ecf20Sopenharmony_ci			  buffer[0], buffer[1], buffer[2], buffer[3]);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
4858c2ecf20Sopenharmony_ci		if (4 != rc)
4868c2ecf20Sopenharmony_ci			tuner_warn("i2c i/o error: rc == %d (should be 4)\n",
4878c2ecf20Sopenharmony_ci				   rc);
4888c2ecf20Sopenharmony_ci		break;
4898c2ecf20Sopenharmony_ci	}
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	return 0;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	switch (priv->type) {
5008c2ecf20Sopenharmony_ci	case TUNER_TENA_9533_DI:
5018c2ecf20Sopenharmony_ci	case TUNER_YMEC_TVF_5533MF:
5028c2ecf20Sopenharmony_ci		tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n");
5038c2ecf20Sopenharmony_ci		return -EINVAL;
5048c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FM1216ME_MK3:
5058c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FM1236_MK3:
5068c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FMD1216ME_MK3:
5078c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FMD1216MEX_MK3:
5088c2ecf20Sopenharmony_ci	case TUNER_LG_NTSC_TAPE:
5098c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FM1256_IH3:
5108c2ecf20Sopenharmony_ci	case TUNER_TCL_MF02GIP_5N:
5118c2ecf20Sopenharmony_ci		buffer[3] = 0x19;
5128c2ecf20Sopenharmony_ci		break;
5138c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FM1216MK5:
5148c2ecf20Sopenharmony_ci		buffer[2] = 0x88;
5158c2ecf20Sopenharmony_ci		buffer[3] = 0x09;
5168c2ecf20Sopenharmony_ci		break;
5178c2ecf20Sopenharmony_ci	case TUNER_TNF_5335MF:
5188c2ecf20Sopenharmony_ci		buffer[3] = 0x11;
5198c2ecf20Sopenharmony_ci		break;
5208c2ecf20Sopenharmony_ci	case TUNER_LG_PAL_FM:
5218c2ecf20Sopenharmony_ci		buffer[3] = 0xa5;
5228c2ecf20Sopenharmony_ci		break;
5238c2ecf20Sopenharmony_ci	case TUNER_THOMSON_DTT761X:
5248c2ecf20Sopenharmony_ci		buffer[3] = 0x39;
5258c2ecf20Sopenharmony_ci		break;
5268c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FQ1216LME_MK3:
5278c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FQ1236_MK5:
5288c2ecf20Sopenharmony_ci		tuner_err("This tuner doesn't have FM\n");
5298c2ecf20Sopenharmony_ci		/* Set the low band for sanity, since it covers 88-108 MHz */
5308c2ecf20Sopenharmony_ci		buffer[3] = 0x01;
5318c2ecf20Sopenharmony_ci		break;
5328c2ecf20Sopenharmony_ci	case TUNER_MICROTUNE_4049FM5:
5338c2ecf20Sopenharmony_ci	default:
5348c2ecf20Sopenharmony_ci		buffer[3] = 0xa4;
5358c2ecf20Sopenharmony_ci		break;
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	return 0;
5398c2ecf20Sopenharmony_ci}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------- */
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cistatic int simple_set_tv_freq(struct dvb_frontend *fe,
5448c2ecf20Sopenharmony_ci			      struct analog_parameters *params)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
5478c2ecf20Sopenharmony_ci	u8 config, cb;
5488c2ecf20Sopenharmony_ci	u16 div;
5498c2ecf20Sopenharmony_ci	u8 buffer[4];
5508c2ecf20Sopenharmony_ci	int rc, IFPCoff, i;
5518c2ecf20Sopenharmony_ci	enum param_type desired_type;
5528c2ecf20Sopenharmony_ci	struct tuner_params *t_params;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	/* IFPCoff = Video Intermediate Frequency - Vif:
5558c2ecf20Sopenharmony_ci		940  =16*58.75  NTSC/J (Japan)
5568c2ecf20Sopenharmony_ci		732  =16*45.75  M/N STD
5578c2ecf20Sopenharmony_ci		704  =16*44     ATSC (at DVB code)
5588c2ecf20Sopenharmony_ci		632  =16*39.50  I U.K.
5598c2ecf20Sopenharmony_ci		622.4=16*38.90  B/G D/K I, L STD
5608c2ecf20Sopenharmony_ci		592  =16*37.00  D China
5618c2ecf20Sopenharmony_ci		590  =16.36.875 B Australia
5628c2ecf20Sopenharmony_ci		543.2=16*33.95  L' STD
5638c2ecf20Sopenharmony_ci		171.2=16*10.70  FM Radio (at set_radio_freq)
5648c2ecf20Sopenharmony_ci	*/
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	if (params->std == V4L2_STD_NTSC_M_JP) {
5678c2ecf20Sopenharmony_ci		IFPCoff      = 940;
5688c2ecf20Sopenharmony_ci		desired_type = TUNER_PARAM_TYPE_NTSC;
5698c2ecf20Sopenharmony_ci	} else if ((params->std & V4L2_STD_MN) &&
5708c2ecf20Sopenharmony_ci		  !(params->std & ~V4L2_STD_MN)) {
5718c2ecf20Sopenharmony_ci		IFPCoff      = 732;
5728c2ecf20Sopenharmony_ci		desired_type = TUNER_PARAM_TYPE_NTSC;
5738c2ecf20Sopenharmony_ci	} else if (params->std == V4L2_STD_SECAM_LC) {
5748c2ecf20Sopenharmony_ci		IFPCoff      = 543;
5758c2ecf20Sopenharmony_ci		desired_type = TUNER_PARAM_TYPE_SECAM;
5768c2ecf20Sopenharmony_ci	} else {
5778c2ecf20Sopenharmony_ci		IFPCoff      = 623;
5788c2ecf20Sopenharmony_ci		desired_type = TUNER_PARAM_TYPE_PAL;
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	t_params = simple_tuner_params(fe, desired_type);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	i = simple_config_lookup(fe, t_params, &params->frequency,
5848c2ecf20Sopenharmony_ci				 &config, &cb);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	div = params->frequency + IFPCoff + offset;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
5898c2ecf20Sopenharmony_ci		  params->frequency / 16, params->frequency % 16 * 100 / 16,
5908c2ecf20Sopenharmony_ci		  IFPCoff / 16, IFPCoff % 16 * 100 / 16,
5918c2ecf20Sopenharmony_ci		  offset / 16, offset % 16 * 100 / 16, div);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	/* tv norm specific stuff for multi-norm tuners */
5948c2ecf20Sopenharmony_ci	simple_std_setup(fe, params, &config, &cb);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
5978c2ecf20Sopenharmony_ci		buffer[0] = config;
5988c2ecf20Sopenharmony_ci		buffer[1] = cb;
5998c2ecf20Sopenharmony_ci		buffer[2] = (div>>8) & 0x7f;
6008c2ecf20Sopenharmony_ci		buffer[3] = div      & 0xff;
6018c2ecf20Sopenharmony_ci	} else {
6028c2ecf20Sopenharmony_ci		buffer[0] = (div>>8) & 0x7f;
6038c2ecf20Sopenharmony_ci		buffer[1] = div      & 0xff;
6048c2ecf20Sopenharmony_ci		buffer[2] = config;
6058c2ecf20Sopenharmony_ci		buffer[3] = cb;
6068c2ecf20Sopenharmony_ci	}
6078c2ecf20Sopenharmony_ci	priv->last_div = div;
6088c2ecf20Sopenharmony_ci	if (t_params->has_tda9887) {
6098c2ecf20Sopenharmony_ci		struct v4l2_priv_tun_config tda9887_cfg;
6108c2ecf20Sopenharmony_ci		int tda_config = 0;
6118c2ecf20Sopenharmony_ci		int is_secam_l = (params->std & (V4L2_STD_SECAM_L |
6128c2ecf20Sopenharmony_ci						 V4L2_STD_SECAM_LC)) &&
6138c2ecf20Sopenharmony_ci			!(params->std & ~(V4L2_STD_SECAM_L |
6148c2ecf20Sopenharmony_ci					  V4L2_STD_SECAM_LC));
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci		tda9887_cfg.tuner = TUNER_TDA9887;
6178c2ecf20Sopenharmony_ci		tda9887_cfg.priv  = &tda_config;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci		if (params->std == V4L2_STD_SECAM_LC) {
6208c2ecf20Sopenharmony_ci			if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
6218c2ecf20Sopenharmony_ci				tda_config |= TDA9887_PORT1_ACTIVE;
6228c2ecf20Sopenharmony_ci			if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
6238c2ecf20Sopenharmony_ci				tda_config |= TDA9887_PORT2_ACTIVE;
6248c2ecf20Sopenharmony_ci		} else {
6258c2ecf20Sopenharmony_ci			if (t_params->port1_active)
6268c2ecf20Sopenharmony_ci				tda_config |= TDA9887_PORT1_ACTIVE;
6278c2ecf20Sopenharmony_ci			if (t_params->port2_active)
6288c2ecf20Sopenharmony_ci				tda_config |= TDA9887_PORT2_ACTIVE;
6298c2ecf20Sopenharmony_ci		}
6308c2ecf20Sopenharmony_ci		if (t_params->intercarrier_mode)
6318c2ecf20Sopenharmony_ci			tda_config |= TDA9887_INTERCARRIER;
6328c2ecf20Sopenharmony_ci		if (is_secam_l) {
6338c2ecf20Sopenharmony_ci			if (i == 0 && t_params->default_top_secam_low)
6348c2ecf20Sopenharmony_ci				tda_config |= TDA9887_TOP(t_params->default_top_secam_low);
6358c2ecf20Sopenharmony_ci			else if (i == 1 && t_params->default_top_secam_mid)
6368c2ecf20Sopenharmony_ci				tda_config |= TDA9887_TOP(t_params->default_top_secam_mid);
6378c2ecf20Sopenharmony_ci			else if (t_params->default_top_secam_high)
6388c2ecf20Sopenharmony_ci				tda_config |= TDA9887_TOP(t_params->default_top_secam_high);
6398c2ecf20Sopenharmony_ci		} else {
6408c2ecf20Sopenharmony_ci			if (i == 0 && t_params->default_top_low)
6418c2ecf20Sopenharmony_ci				tda_config |= TDA9887_TOP(t_params->default_top_low);
6428c2ecf20Sopenharmony_ci			else if (i == 1 && t_params->default_top_mid)
6438c2ecf20Sopenharmony_ci				tda_config |= TDA9887_TOP(t_params->default_top_mid);
6448c2ecf20Sopenharmony_ci			else if (t_params->default_top_high)
6458c2ecf20Sopenharmony_ci				tda_config |= TDA9887_TOP(t_params->default_top_high);
6468c2ecf20Sopenharmony_ci		}
6478c2ecf20Sopenharmony_ci		if (t_params->default_pll_gating_18)
6488c2ecf20Sopenharmony_ci			tda_config |= TDA9887_GATING_18;
6498c2ecf20Sopenharmony_ci		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
6508c2ecf20Sopenharmony_ci				    &tda9887_cfg);
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
6538c2ecf20Sopenharmony_ci		  buffer[0], buffer[1], buffer[2], buffer[3]);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
6568c2ecf20Sopenharmony_ci	if (4 != rc)
6578c2ecf20Sopenharmony_ci		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	simple_post_tune(fe, &buffer[0], div, config, cb);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	return 0;
6628c2ecf20Sopenharmony_ci}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_cistatic int simple_set_radio_freq(struct dvb_frontend *fe,
6658c2ecf20Sopenharmony_ci				 struct analog_parameters *params)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	struct tunertype *tun;
6688c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
6698c2ecf20Sopenharmony_ci	u8 buffer[4];
6708c2ecf20Sopenharmony_ci	u16 div;
6718c2ecf20Sopenharmony_ci	int rc, j;
6728c2ecf20Sopenharmony_ci	struct tuner_params *t_params;
6738c2ecf20Sopenharmony_ci	unsigned int freq = params->frequency;
6748c2ecf20Sopenharmony_ci	bool mono = params->audmode == V4L2_TUNER_MODE_MONO;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	tun = priv->tun;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	for (j = tun->count-1; j > 0; j--)
6798c2ecf20Sopenharmony_ci		if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO)
6808c2ecf20Sopenharmony_ci			break;
6818c2ecf20Sopenharmony_ci	/* default t_params (j=0) will be used if desired type wasn't found */
6828c2ecf20Sopenharmony_ci	t_params = &tun->params[j];
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	/* Select Radio 1st IF used */
6858c2ecf20Sopenharmony_ci	switch (t_params->radio_if) {
6868c2ecf20Sopenharmony_ci	case 0: /* 10.7 MHz */
6878c2ecf20Sopenharmony_ci		freq += (unsigned int)(10.7*16000);
6888c2ecf20Sopenharmony_ci		break;
6898c2ecf20Sopenharmony_ci	case 1: /* 33.3 MHz */
6908c2ecf20Sopenharmony_ci		freq += (unsigned int)(33.3*16000);
6918c2ecf20Sopenharmony_ci		break;
6928c2ecf20Sopenharmony_ci	case 2: /* 41.3 MHz */
6938c2ecf20Sopenharmony_ci		freq += (unsigned int)(41.3*16000);
6948c2ecf20Sopenharmony_ci		break;
6958c2ecf20Sopenharmony_ci	default:
6968c2ecf20Sopenharmony_ci		tuner_warn("Unsupported radio_if value %d\n",
6978c2ecf20Sopenharmony_ci			   t_params->radio_if);
6988c2ecf20Sopenharmony_ci		return 0;
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
7028c2ecf20Sopenharmony_ci		    TUNER_RATIO_SELECT_50; /* 50 kHz step */
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	/* Bandswitch byte */
7058c2ecf20Sopenharmony_ci	if (simple_radio_bandswitch(fe, &buffer[0]))
7068c2ecf20Sopenharmony_ci		return 0;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	/* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
7098c2ecf20Sopenharmony_ci	   freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
7108c2ecf20Sopenharmony_ci	   freq * (1/800) */
7118c2ecf20Sopenharmony_ci	div = (freq + 400) / 800;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
7148c2ecf20Sopenharmony_ci		buffer[0] = buffer[2];
7158c2ecf20Sopenharmony_ci		buffer[1] = buffer[3];
7168c2ecf20Sopenharmony_ci		buffer[2] = (div>>8) & 0x7f;
7178c2ecf20Sopenharmony_ci		buffer[3] = div      & 0xff;
7188c2ecf20Sopenharmony_ci	} else {
7198c2ecf20Sopenharmony_ci		buffer[0] = (div>>8) & 0x7f;
7208c2ecf20Sopenharmony_ci		buffer[1] = div      & 0xff;
7218c2ecf20Sopenharmony_ci	}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
7248c2ecf20Sopenharmony_ci	       buffer[0], buffer[1], buffer[2], buffer[3]);
7258c2ecf20Sopenharmony_ci	priv->last_div = div;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	if (t_params->has_tda9887) {
7288c2ecf20Sopenharmony_ci		int config = 0;
7298c2ecf20Sopenharmony_ci		struct v4l2_priv_tun_config tda9887_cfg;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci		tda9887_cfg.tuner = TUNER_TDA9887;
7328c2ecf20Sopenharmony_ci		tda9887_cfg.priv = &config;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci		if (t_params->port1_active &&
7358c2ecf20Sopenharmony_ci		    !t_params->port1_fm_high_sensitivity)
7368c2ecf20Sopenharmony_ci			config |= TDA9887_PORT1_ACTIVE;
7378c2ecf20Sopenharmony_ci		if (t_params->port2_active &&
7388c2ecf20Sopenharmony_ci		    !t_params->port2_fm_high_sensitivity)
7398c2ecf20Sopenharmony_ci			config |= TDA9887_PORT2_ACTIVE;
7408c2ecf20Sopenharmony_ci		if (t_params->intercarrier_mode)
7418c2ecf20Sopenharmony_ci			config |= TDA9887_INTERCARRIER;
7428c2ecf20Sopenharmony_ci		if (t_params->port1_set_for_fm_mono && mono)
7438c2ecf20Sopenharmony_ci			config &= ~TDA9887_PORT1_ACTIVE;
7448c2ecf20Sopenharmony_ci		if (t_params->fm_gain_normal)
7458c2ecf20Sopenharmony_ci			config |= TDA9887_GAIN_NORMAL;
7468c2ecf20Sopenharmony_ci		if (t_params->radio_if == 2)
7478c2ecf20Sopenharmony_ci			config |= TDA9887_RIF_41_3;
7488c2ecf20Sopenharmony_ci		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
7498c2ecf20Sopenharmony_ci				    &tda9887_cfg);
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
7528c2ecf20Sopenharmony_ci	if (4 != rc)
7538c2ecf20Sopenharmony_ci		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	/* Write AUX byte */
7568c2ecf20Sopenharmony_ci	switch (priv->type) {
7578c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FM1216ME_MK3:
7588c2ecf20Sopenharmony_ci		buffer[2] = 0x98;
7598c2ecf20Sopenharmony_ci		buffer[3] = 0x20; /* set TOP AGC */
7608c2ecf20Sopenharmony_ci		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
7618c2ecf20Sopenharmony_ci		if (4 != rc)
7628c2ecf20Sopenharmony_ci			tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
7638c2ecf20Sopenharmony_ci		break;
7648c2ecf20Sopenharmony_ci	}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	return 0;
7678c2ecf20Sopenharmony_ci}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_cistatic int simple_set_params(struct dvb_frontend *fe,
7708c2ecf20Sopenharmony_ci			     struct analog_parameters *params)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
7738c2ecf20Sopenharmony_ci	int ret = -EINVAL;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	if (priv->i2c_props.adap == NULL)
7768c2ecf20Sopenharmony_ci		return -EINVAL;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	switch (params->mode) {
7798c2ecf20Sopenharmony_ci	case V4L2_TUNER_RADIO:
7808c2ecf20Sopenharmony_ci		priv->radio_mode = true;
7818c2ecf20Sopenharmony_ci		ret = simple_set_radio_freq(fe, params);
7828c2ecf20Sopenharmony_ci		priv->frequency = params->frequency * 125 / 2;
7838c2ecf20Sopenharmony_ci		break;
7848c2ecf20Sopenharmony_ci	case V4L2_TUNER_ANALOG_TV:
7858c2ecf20Sopenharmony_ci	case V4L2_TUNER_DIGITAL_TV:
7868c2ecf20Sopenharmony_ci		priv->radio_mode = false;
7878c2ecf20Sopenharmony_ci		ret = simple_set_tv_freq(fe, params);
7888c2ecf20Sopenharmony_ci		priv->frequency = params->frequency * 62500;
7898c2ecf20Sopenharmony_ci		break;
7908c2ecf20Sopenharmony_ci	}
7918c2ecf20Sopenharmony_ci	priv->bandwidth = 0;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	return ret;
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
7978c2ecf20Sopenharmony_ci			   const u32 delsys,
7988c2ecf20Sopenharmony_ci			   const u32 frequency,
7998c2ecf20Sopenharmony_ci			   const u32 bandwidth)
8008c2ecf20Sopenharmony_ci{
8018c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	switch (priv->type) {
8048c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FMD1216ME_MK3:
8058c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FMD1216MEX_MK3:
8068c2ecf20Sopenharmony_ci		if (bandwidth == 8000000 &&
8078c2ecf20Sopenharmony_ci		    frequency >= 158870000)
8088c2ecf20Sopenharmony_ci			buf[3] |= 0x08;
8098c2ecf20Sopenharmony_ci		break;
8108c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_TD1316:
8118c2ecf20Sopenharmony_ci		/* determine band */
8128c2ecf20Sopenharmony_ci		buf[3] |= (frequency < 161000000) ? 1 :
8138c2ecf20Sopenharmony_ci			  (frequency < 444000000) ? 2 : 4;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci		/* setup PLL filter */
8168c2ecf20Sopenharmony_ci		if (bandwidth == 8000000)
8178c2ecf20Sopenharmony_ci			buf[3] |= 1 << 3;
8188c2ecf20Sopenharmony_ci		break;
8198c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_TUV1236D:
8208c2ecf20Sopenharmony_ci	case TUNER_PHILIPS_FCV1236D:
8218c2ecf20Sopenharmony_ci	{
8228c2ecf20Sopenharmony_ci		unsigned int new_rf;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci		if (dtv_input[priv->nr])
8258c2ecf20Sopenharmony_ci			new_rf = dtv_input[priv->nr];
8268c2ecf20Sopenharmony_ci		else
8278c2ecf20Sopenharmony_ci			switch (delsys) {
8288c2ecf20Sopenharmony_ci			case SYS_DVBC_ANNEX_B:
8298c2ecf20Sopenharmony_ci				new_rf = 1;
8308c2ecf20Sopenharmony_ci				break;
8318c2ecf20Sopenharmony_ci			case SYS_ATSC:
8328c2ecf20Sopenharmony_ci			default:
8338c2ecf20Sopenharmony_ci				new_rf = 0;
8348c2ecf20Sopenharmony_ci				break;
8358c2ecf20Sopenharmony_ci			}
8368c2ecf20Sopenharmony_ci		simple_set_rf_input(fe, &buf[2], &buf[3], new_rf);
8378c2ecf20Sopenharmony_ci		break;
8388c2ecf20Sopenharmony_ci	}
8398c2ecf20Sopenharmony_ci	default:
8408c2ecf20Sopenharmony_ci		break;
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_cistatic u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
8458c2ecf20Sopenharmony_ci				const u32 delsys,
8468c2ecf20Sopenharmony_ci				const u32 freq,
8478c2ecf20Sopenharmony_ci				const u32 bw)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	/* This function returns the tuned frequency on success, 0 on error */
8508c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
8518c2ecf20Sopenharmony_ci	struct tunertype *tun = priv->tun;
8528c2ecf20Sopenharmony_ci	struct tuner_params *t_params;
8538c2ecf20Sopenharmony_ci	u8 config, cb;
8548c2ecf20Sopenharmony_ci	u32 div;
8558c2ecf20Sopenharmony_ci	int ret;
8568c2ecf20Sopenharmony_ci	u32 frequency = freq / 62500;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	if (!tun->stepsize) {
8598c2ecf20Sopenharmony_ci		/* tuner-core was loaded before the digital tuner was
8608c2ecf20Sopenharmony_ci		 * configured and somehow picked the wrong tuner type */
8618c2ecf20Sopenharmony_ci		tuner_err("attempt to treat tuner %d (%s) as digital tuner without stepsize defined.\n",
8628c2ecf20Sopenharmony_ci			  priv->type, priv->tun->name);
8638c2ecf20Sopenharmony_ci		return 0; /* failure */
8648c2ecf20Sopenharmony_ci	}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
8678c2ecf20Sopenharmony_ci	ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
8688c2ecf20Sopenharmony_ci	if (ret < 0)
8698c2ecf20Sopenharmony_ci		return 0; /* failure */
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	div = ((frequency + t_params->iffreq) * 62500 + offset +
8728c2ecf20Sopenharmony_ci	       tun->stepsize/2) / tun->stepsize;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	buf[0] = div >> 8;
8758c2ecf20Sopenharmony_ci	buf[1] = div & 0xff;
8768c2ecf20Sopenharmony_ci	buf[2] = config;
8778c2ecf20Sopenharmony_ci	buf[3] = cb;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	simple_set_dvb(fe, buf, delsys, freq, bw);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
8828c2ecf20Sopenharmony_ci		  tun->name, div, buf[0], buf[1], buf[2], buf[3]);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	/* calculate the frequency we set it to */
8858c2ecf20Sopenharmony_ci	return (div * tun->stepsize) - t_params->iffreq;
8868c2ecf20Sopenharmony_ci}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_cistatic int simple_dvb_calc_regs(struct dvb_frontend *fe,
8898c2ecf20Sopenharmony_ci				u8 *buf, int buf_len)
8908c2ecf20Sopenharmony_ci{
8918c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
8928c2ecf20Sopenharmony_ci	u32 delsys = c->delivery_system;
8938c2ecf20Sopenharmony_ci	u32 bw = c->bandwidth_hz;
8948c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
8958c2ecf20Sopenharmony_ci	u32 frequency;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	if (buf_len < 5)
8988c2ecf20Sopenharmony_ci		return -EINVAL;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	frequency = simple_dvb_configure(fe, buf+1, delsys, c->frequency, bw);
9018c2ecf20Sopenharmony_ci	if (frequency == 0)
9028c2ecf20Sopenharmony_ci		return -EINVAL;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	buf[0] = priv->i2c_props.addr;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	priv->frequency = frequency;
9078c2ecf20Sopenharmony_ci	priv->bandwidth = c->bandwidth_hz;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	return 5;
9108c2ecf20Sopenharmony_ci}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_cistatic int simple_dvb_set_params(struct dvb_frontend *fe)
9138c2ecf20Sopenharmony_ci{
9148c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
9158c2ecf20Sopenharmony_ci	u32 delsys = c->delivery_system;
9168c2ecf20Sopenharmony_ci	u32 bw = c->bandwidth_hz;
9178c2ecf20Sopenharmony_ci	u32 freq = c->frequency;
9188c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
9198c2ecf20Sopenharmony_ci	u32 frequency;
9208c2ecf20Sopenharmony_ci	u32 prev_freq, prev_bw;
9218c2ecf20Sopenharmony_ci	int ret;
9228c2ecf20Sopenharmony_ci	u8 buf[5];
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	if (priv->i2c_props.adap == NULL)
9258c2ecf20Sopenharmony_ci		return -EINVAL;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	prev_freq = priv->frequency;
9288c2ecf20Sopenharmony_ci	prev_bw   = priv->bandwidth;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	frequency = simple_dvb_configure(fe, buf+1, delsys, freq, bw);
9318c2ecf20Sopenharmony_ci	if (frequency == 0)
9328c2ecf20Sopenharmony_ci		return -EINVAL;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	buf[0] = priv->i2c_props.addr;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	priv->frequency = frequency;
9378c2ecf20Sopenharmony_ci	priv->bandwidth = bw;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	/* put analog demod in standby when tuning digital */
9408c2ecf20Sopenharmony_ci	if (fe->ops.analog_ops.standby)
9418c2ecf20Sopenharmony_ci		fe->ops.analog_ops.standby(fe);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
9448c2ecf20Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	/* buf[0] contains the i2c address, but *
9478c2ecf20Sopenharmony_ci	 * we already have it in i2c_props.addr */
9488c2ecf20Sopenharmony_ci	ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4);
9498c2ecf20Sopenharmony_ci	if (ret != 4)
9508c2ecf20Sopenharmony_ci		goto fail;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	return 0;
9538c2ecf20Sopenharmony_cifail:
9548c2ecf20Sopenharmony_ci	/* calc_regs sets frequency and bandwidth. if we failed, unset them */
9558c2ecf20Sopenharmony_ci	priv->frequency = prev_freq;
9568c2ecf20Sopenharmony_ci	priv->bandwidth = prev_bw;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	return ret;
9598c2ecf20Sopenharmony_ci}
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_cistatic int simple_init(struct dvb_frontend *fe)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (priv->i2c_props.adap == NULL)
9668c2ecf20Sopenharmony_ci		return -EINVAL;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	if (priv->tun->initdata) {
9698c2ecf20Sopenharmony_ci		int ret;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci		if (fe->ops.i2c_gate_ctrl)
9728c2ecf20Sopenharmony_ci			fe->ops.i2c_gate_ctrl(fe, 1);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci		ret = tuner_i2c_xfer_send(&priv->i2c_props,
9758c2ecf20Sopenharmony_ci					  priv->tun->initdata + 1,
9768c2ecf20Sopenharmony_ci					  priv->tun->initdata[0]);
9778c2ecf20Sopenharmony_ci		if (ret != priv->tun->initdata[0])
9788c2ecf20Sopenharmony_ci			return ret;
9798c2ecf20Sopenharmony_ci	}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	return 0;
9828c2ecf20Sopenharmony_ci}
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_cistatic int simple_sleep(struct dvb_frontend *fe)
9858c2ecf20Sopenharmony_ci{
9868c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	if (priv->i2c_props.adap == NULL)
9898c2ecf20Sopenharmony_ci		return -EINVAL;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	if (priv->tun->sleepdata) {
9928c2ecf20Sopenharmony_ci		int ret;
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci		if (fe->ops.i2c_gate_ctrl)
9958c2ecf20Sopenharmony_ci			fe->ops.i2c_gate_ctrl(fe, 1);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci		ret = tuner_i2c_xfer_send(&priv->i2c_props,
9988c2ecf20Sopenharmony_ci					  priv->tun->sleepdata + 1,
9998c2ecf20Sopenharmony_ci					  priv->tun->sleepdata[0]);
10008c2ecf20Sopenharmony_ci		if (ret != priv->tun->sleepdata[0])
10018c2ecf20Sopenharmony_ci			return ret;
10028c2ecf20Sopenharmony_ci	}
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	return 0;
10058c2ecf20Sopenharmony_ci}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_cistatic void simple_release(struct dvb_frontend *fe)
10088c2ecf20Sopenharmony_ci{
10098c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	mutex_lock(&tuner_simple_list_mutex);
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	if (priv)
10148c2ecf20Sopenharmony_ci		hybrid_tuner_release_state(priv);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	mutex_unlock(&tuner_simple_list_mutex);
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	fe->tuner_priv = NULL;
10198c2ecf20Sopenharmony_ci}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_cistatic int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency)
10228c2ecf20Sopenharmony_ci{
10238c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
10248c2ecf20Sopenharmony_ci	*frequency = priv->frequency;
10258c2ecf20Sopenharmony_ci	return 0;
10268c2ecf20Sopenharmony_ci}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_cistatic int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
10298c2ecf20Sopenharmony_ci{
10308c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
10318c2ecf20Sopenharmony_ci	*bandwidth = priv->bandwidth;
10328c2ecf20Sopenharmony_ci	return 0;
10338c2ecf20Sopenharmony_ci}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops simple_tuner_ops = {
10368c2ecf20Sopenharmony_ci	.init              = simple_init,
10378c2ecf20Sopenharmony_ci	.sleep             = simple_sleep,
10388c2ecf20Sopenharmony_ci	.set_analog_params = simple_set_params,
10398c2ecf20Sopenharmony_ci	.set_params        = simple_dvb_set_params,
10408c2ecf20Sopenharmony_ci	.calc_regs         = simple_dvb_calc_regs,
10418c2ecf20Sopenharmony_ci	.release           = simple_release,
10428c2ecf20Sopenharmony_ci	.get_frequency     = simple_get_frequency,
10438c2ecf20Sopenharmony_ci	.get_bandwidth     = simple_get_bandwidth,
10448c2ecf20Sopenharmony_ci	.get_status        = simple_get_status,
10458c2ecf20Sopenharmony_ci	.get_rf_strength   = simple_get_rf_strength,
10468c2ecf20Sopenharmony_ci};
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_cistruct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
10498c2ecf20Sopenharmony_ci					 struct i2c_adapter *i2c_adap,
10508c2ecf20Sopenharmony_ci					 u8 i2c_addr,
10518c2ecf20Sopenharmony_ci					 unsigned int type)
10528c2ecf20Sopenharmony_ci{
10538c2ecf20Sopenharmony_ci	struct tuner_simple_priv *priv = NULL;
10548c2ecf20Sopenharmony_ci	int instance;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	if (type >= tuner_count) {
10578c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n",
10588c2ecf20Sopenharmony_ci		       __func__, type, tuner_count-1);
10598c2ecf20Sopenharmony_ci		return NULL;
10608c2ecf20Sopenharmony_ci	}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	/* If i2c_adap is set, check that the tuner is at the correct address.
10638c2ecf20Sopenharmony_ci	 * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly
10648c2ecf20Sopenharmony_ci	 * by the digital demod via calc_regs.
10658c2ecf20Sopenharmony_ci	 */
10668c2ecf20Sopenharmony_ci	if (i2c_adap != NULL) {
10678c2ecf20Sopenharmony_ci		u8 b[1];
10688c2ecf20Sopenharmony_ci		struct i2c_msg msg = {
10698c2ecf20Sopenharmony_ci			.addr = i2c_addr, .flags = I2C_M_RD,
10708c2ecf20Sopenharmony_ci			.buf = b, .len = 1,
10718c2ecf20Sopenharmony_ci		};
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci		if (fe->ops.i2c_gate_ctrl)
10748c2ecf20Sopenharmony_ci			fe->ops.i2c_gate_ctrl(fe, 1);
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci		if (1 != i2c_transfer(i2c_adap, &msg, 1))
10778c2ecf20Sopenharmony_ci			printk(KERN_WARNING "tuner-simple %d-%04x: unable to probe %s, proceeding anyway.",
10788c2ecf20Sopenharmony_ci			       i2c_adapter_id(i2c_adap), i2c_addr,
10798c2ecf20Sopenharmony_ci			       tuners[type].name);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci		if (fe->ops.i2c_gate_ctrl)
10828c2ecf20Sopenharmony_ci			fe->ops.i2c_gate_ctrl(fe, 0);
10838c2ecf20Sopenharmony_ci	}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	mutex_lock(&tuner_simple_list_mutex);
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv,
10888c2ecf20Sopenharmony_ci					      hybrid_tuner_instance_list,
10898c2ecf20Sopenharmony_ci					      i2c_adap, i2c_addr,
10908c2ecf20Sopenharmony_ci					      "tuner-simple");
10918c2ecf20Sopenharmony_ci	switch (instance) {
10928c2ecf20Sopenharmony_ci	case 0:
10938c2ecf20Sopenharmony_ci		mutex_unlock(&tuner_simple_list_mutex);
10948c2ecf20Sopenharmony_ci		return NULL;
10958c2ecf20Sopenharmony_ci	case 1:
10968c2ecf20Sopenharmony_ci		fe->tuner_priv = priv;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci		priv->type = type;
10998c2ecf20Sopenharmony_ci		priv->tun  = &tuners[type];
11008c2ecf20Sopenharmony_ci		priv->nr   = simple_devcount++;
11018c2ecf20Sopenharmony_ci		break;
11028c2ecf20Sopenharmony_ci	default:
11038c2ecf20Sopenharmony_ci		fe->tuner_priv = priv;
11048c2ecf20Sopenharmony_ci		break;
11058c2ecf20Sopenharmony_ci	}
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	mutex_unlock(&tuner_simple_list_mutex);
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	memcpy(&fe->ops.tuner_ops, &simple_tuner_ops,
11108c2ecf20Sopenharmony_ci	       sizeof(struct dvb_tuner_ops));
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	if (type != priv->type)
11138c2ecf20Sopenharmony_ci		tuner_warn("couldn't set type to %d. Using %d (%s) instead\n",
11148c2ecf20Sopenharmony_ci			    type, priv->type, priv->tun->name);
11158c2ecf20Sopenharmony_ci	else
11168c2ecf20Sopenharmony_ci		tuner_info("type set to %d (%s)\n",
11178c2ecf20Sopenharmony_ci			   priv->type, priv->tun->name);
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	if ((debug) || ((atv_input[priv->nr] > 0) ||
11208c2ecf20Sopenharmony_ci			(dtv_input[priv->nr] > 0))) {
11218c2ecf20Sopenharmony_ci		if (0 == atv_input[priv->nr])
11228c2ecf20Sopenharmony_ci			tuner_info("tuner %d atv rf input will be autoselected\n",
11238c2ecf20Sopenharmony_ci				   priv->nr);
11248c2ecf20Sopenharmony_ci		else
11258c2ecf20Sopenharmony_ci			tuner_info("tuner %d atv rf input will be set to input %d (insmod option)\n",
11268c2ecf20Sopenharmony_ci				   priv->nr, atv_input[priv->nr]);
11278c2ecf20Sopenharmony_ci		if (0 == dtv_input[priv->nr])
11288c2ecf20Sopenharmony_ci			tuner_info("tuner %d dtv rf input will be autoselected\n",
11298c2ecf20Sopenharmony_ci				   priv->nr);
11308c2ecf20Sopenharmony_ci		else
11318c2ecf20Sopenharmony_ci			tuner_info("tuner %d dtv rf input will be set to input %d (insmod option)\n",
11328c2ecf20Sopenharmony_ci				   priv->nr, dtv_input[priv->nr]);
11338c2ecf20Sopenharmony_ci	}
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	strscpy(fe->ops.tuner_ops.info.name, priv->tun->name,
11368c2ecf20Sopenharmony_ci		sizeof(fe->ops.tuner_ops.info.name));
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	return fe;
11398c2ecf20Sopenharmony_ci}
11408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(simple_tuner_attach);
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");
11438c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
11448c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1145