162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * i2c tv tuner chip device driver
462306a36Sopenharmony_ci * controls all those simple 4-control-bytes style tuners.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This "tuner-simple" module was split apart from the original "tuner" module.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci#include <linux/i2c.h>
1062306a36Sopenharmony_ci#include <linux/videodev2.h>
1162306a36Sopenharmony_ci#include <media/tuner.h>
1262306a36Sopenharmony_ci#include <media/v4l2-common.h>
1362306a36Sopenharmony_ci#include <media/tuner-types.h>
1462306a36Sopenharmony_ci#include "tuner-i2c.h"
1562306a36Sopenharmony_ci#include "tuner-simple.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic int debug;
1862306a36Sopenharmony_cimodule_param(debug, int, 0644);
1962306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "enable verbose debug messages");
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define TUNER_SIMPLE_MAX 64
2262306a36Sopenharmony_cistatic unsigned int simple_devcount;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic int offset;
2562306a36Sopenharmony_cimodule_param(offset, int, 0664);
2662306a36Sopenharmony_ciMODULE_PARM_DESC(offset, "Allows to specify an offset for tuner");
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic unsigned int atv_input[TUNER_SIMPLE_MAX] = \
2962306a36Sopenharmony_ci			{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
3062306a36Sopenharmony_cistatic unsigned int dtv_input[TUNER_SIMPLE_MAX] = \
3162306a36Sopenharmony_ci			{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
3262306a36Sopenharmony_cimodule_param_array(atv_input, int, NULL, 0644);
3362306a36Sopenharmony_cimodule_param_array(dtv_input, int, NULL, 0644);
3462306a36Sopenharmony_ciMODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect");
3562306a36Sopenharmony_ciMODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect");
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* ---------------------------------------------------------------------- */
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* tv standard selection for Temic 4046 FM5
4062306a36Sopenharmony_ci   this value takes the low bits of control byte 2
4162306a36Sopenharmony_ci   from datasheet Rev.01, Feb.00
4262306a36Sopenharmony_ci     standard     BG      I       L       L2      D
4362306a36Sopenharmony_ci     picture IF   38.9    38.9    38.9    33.95   38.9
4462306a36Sopenharmony_ci     sound 1      33.4    32.9    32.4    40.45   32.4
4562306a36Sopenharmony_ci     sound 2      33.16
4662306a36Sopenharmony_ci     NICAM        33.05   32.348  33.05           33.05
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_ci#define TEMIC_SET_PAL_I         0x05
4962306a36Sopenharmony_ci#define TEMIC_SET_PAL_DK        0x09
5062306a36Sopenharmony_ci#define TEMIC_SET_PAL_L         0x0a /* SECAM ? */
5162306a36Sopenharmony_ci#define TEMIC_SET_PAL_L2        0x0b /* change IF ! */
5262306a36Sopenharmony_ci#define TEMIC_SET_PAL_BG        0x0c
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* tv tuner system standard selection for Philips FQ1216ME
5562306a36Sopenharmony_ci   this value takes the low bits of control byte 2
5662306a36Sopenharmony_ci   from datasheet "1999 Nov 16" (supersedes "1999 Mar 23")
5762306a36Sopenharmony_ci     standard		BG	DK	I	L	L`
5862306a36Sopenharmony_ci     picture carrier	38.90	38.90	38.90	38.90	33.95
5962306a36Sopenharmony_ci     colour		34.47	34.47	34.47	34.47	38.38
6062306a36Sopenharmony_ci     sound 1		33.40	32.40	32.90	32.40	40.45
6162306a36Sopenharmony_ci     sound 2		33.16	-	-	-	-
6262306a36Sopenharmony_ci     NICAM		33.05	33.05	32.35	33.05	39.80
6362306a36Sopenharmony_ci */
6462306a36Sopenharmony_ci#define PHILIPS_SET_PAL_I	0x01 /* Bit 2 always zero !*/
6562306a36Sopenharmony_ci#define PHILIPS_SET_PAL_BGDK	0x09
6662306a36Sopenharmony_ci#define PHILIPS_SET_PAL_L2	0x0a
6762306a36Sopenharmony_ci#define PHILIPS_SET_PAL_L	0x0b
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* system switching for Philips FI1216MF MK2
7062306a36Sopenharmony_ci   from datasheet "1996 Jul 09",
7162306a36Sopenharmony_ci    standard         BG     L      L'
7262306a36Sopenharmony_ci    picture carrier  38.90  38.90  33.95
7362306a36Sopenharmony_ci    colour	     34.47  34.37  38.38
7462306a36Sopenharmony_ci    sound 1          33.40  32.40  40.45
7562306a36Sopenharmony_ci    sound 2          33.16  -      -
7662306a36Sopenharmony_ci    NICAM            33.05  33.05  39.80
7762306a36Sopenharmony_ci */
7862306a36Sopenharmony_ci#define PHILIPS_MF_SET_STD_BG	0x01 /* Bit 2 must be zero, Bit 3 is system output */
7962306a36Sopenharmony_ci#define PHILIPS_MF_SET_STD_L	0x03 /* Used on Secam France */
8062306a36Sopenharmony_ci#define PHILIPS_MF_SET_STD_LC	0x02 /* Used on SECAM L' */
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/* Control byte */
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci#define TUNER_RATIO_MASK        0x06 /* Bit cb1:cb2 */
8562306a36Sopenharmony_ci#define TUNER_RATIO_SELECT_50   0x00
8662306a36Sopenharmony_ci#define TUNER_RATIO_SELECT_32   0x02
8762306a36Sopenharmony_ci#define TUNER_RATIO_SELECT_166  0x04
8862306a36Sopenharmony_ci#define TUNER_RATIO_SELECT_62   0x06
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#define TUNER_CHARGE_PUMP       0x40  /* Bit cb6 */
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* Status byte */
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#define TUNER_POR	  0x80
9562306a36Sopenharmony_ci#define TUNER_FL          0x40
9662306a36Sopenharmony_ci#define TUNER_MODE        0x38
9762306a36Sopenharmony_ci#define TUNER_AFC         0x07
9862306a36Sopenharmony_ci#define TUNER_SIGNAL      0x07
9962306a36Sopenharmony_ci#define TUNER_STEREO      0x10
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#define TUNER_PLL_LOCKED   0x40
10262306a36Sopenharmony_ci#define TUNER_STEREO_MK3   0x04
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic DEFINE_MUTEX(tuner_simple_list_mutex);
10562306a36Sopenharmony_cistatic LIST_HEAD(hybrid_tuner_instance_list);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistruct tuner_simple_priv {
10862306a36Sopenharmony_ci	unsigned int nr;
10962306a36Sopenharmony_ci	u16 last_div;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	struct tuner_i2c_props i2c_props;
11262306a36Sopenharmony_ci	struct list_head hybrid_tuner_instance_list;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	unsigned int type;
11562306a36Sopenharmony_ci	struct tunertype *tun;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	u32 frequency;
11862306a36Sopenharmony_ci	u32 bandwidth;
11962306a36Sopenharmony_ci	bool radio_mode;
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/* ---------------------------------------------------------------------- */
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic int tuner_read_status(struct dvb_frontend *fe)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
12762306a36Sopenharmony_ci	unsigned char byte;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1))
13062306a36Sopenharmony_ci		return 0;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return byte;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic inline int tuner_signal(const int status)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	return (status & TUNER_SIGNAL) << 13;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic inline int tuner_stereo(const int type, const int status)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	switch (type) {
14362306a36Sopenharmony_ci	case TUNER_PHILIPS_FM1216ME_MK3:
14462306a36Sopenharmony_ci	case TUNER_PHILIPS_FM1236_MK3:
14562306a36Sopenharmony_ci	case TUNER_PHILIPS_FM1256_IH3:
14662306a36Sopenharmony_ci	case TUNER_LG_NTSC_TAPE:
14762306a36Sopenharmony_ci	case TUNER_TCL_MF02GIP_5N:
14862306a36Sopenharmony_ci		return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
14962306a36Sopenharmony_ci	case TUNER_PHILIPS_FM1216MK5:
15062306a36Sopenharmony_ci		return status | TUNER_STEREO;
15162306a36Sopenharmony_ci	default:
15262306a36Sopenharmony_ci		return status & TUNER_STEREO;
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic inline int tuner_islocked(const int status)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	return (status & TUNER_FL);
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic inline int tuner_afcstatus(const int status)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	return (status & TUNER_AFC) - 2;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic int simple_get_status(struct dvb_frontend *fe, u32 *status)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
17062306a36Sopenharmony_ci	int tuner_status;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (priv->i2c_props.adap == NULL)
17362306a36Sopenharmony_ci		return -EINVAL;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	tuner_status = tuner_read_status(fe);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	*status = 0;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (tuner_islocked(tuner_status))
18062306a36Sopenharmony_ci		*status = TUNER_STATUS_LOCKED;
18162306a36Sopenharmony_ci	if (tuner_stereo(priv->type, tuner_status))
18262306a36Sopenharmony_ci		*status |= TUNER_STATUS_STEREO;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status));
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return 0;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
19262306a36Sopenharmony_ci	int signal;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if (priv->i2c_props.adap == NULL || !priv->radio_mode)
19562306a36Sopenharmony_ci		return -EINVAL;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	signal = tuner_signal(tuner_read_status(fe));
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	*strength = signal;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	tuner_dbg("Signal strength: %d\n", signal);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	return 0;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci/* ---------------------------------------------------------------------- */
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic inline char *tuner_param_name(enum param_type type)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	char *name;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	switch (type) {
21362306a36Sopenharmony_ci	case TUNER_PARAM_TYPE_RADIO:
21462306a36Sopenharmony_ci		name = "radio";
21562306a36Sopenharmony_ci		break;
21662306a36Sopenharmony_ci	case TUNER_PARAM_TYPE_PAL:
21762306a36Sopenharmony_ci		name = "pal";
21862306a36Sopenharmony_ci		break;
21962306a36Sopenharmony_ci	case TUNER_PARAM_TYPE_SECAM:
22062306a36Sopenharmony_ci		name = "secam";
22162306a36Sopenharmony_ci		break;
22262306a36Sopenharmony_ci	case TUNER_PARAM_TYPE_NTSC:
22362306a36Sopenharmony_ci		name = "ntsc";
22462306a36Sopenharmony_ci		break;
22562306a36Sopenharmony_ci	case TUNER_PARAM_TYPE_DIGITAL:
22662306a36Sopenharmony_ci		name = "digital";
22762306a36Sopenharmony_ci		break;
22862306a36Sopenharmony_ci	default:
22962306a36Sopenharmony_ci		name = "unknown";
23062306a36Sopenharmony_ci		break;
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci	return name;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic struct tuner_params *simple_tuner_params(struct dvb_frontend *fe,
23662306a36Sopenharmony_ci						enum param_type desired_type)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
23962306a36Sopenharmony_ci	struct tunertype *tun = priv->tun;
24062306a36Sopenharmony_ci	int i;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	for (i = 0; i < tun->count; i++)
24362306a36Sopenharmony_ci		if (desired_type == tun->params[i].type)
24462306a36Sopenharmony_ci			break;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/* use default tuner params if desired_type not available */
24762306a36Sopenharmony_ci	if (i == tun->count) {
24862306a36Sopenharmony_ci		tuner_dbg("desired params (%s) undefined for tuner %d\n",
24962306a36Sopenharmony_ci			  tuner_param_name(desired_type), priv->type);
25062306a36Sopenharmony_ci		i = 0;
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	tuner_dbg("using tuner params #%d (%s)\n", i,
25462306a36Sopenharmony_ci		  tuner_param_name(tun->params[i].type));
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	return &tun->params[i];
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic int simple_config_lookup(struct dvb_frontend *fe,
26062306a36Sopenharmony_ci				struct tuner_params *t_params,
26162306a36Sopenharmony_ci				unsigned *frequency, u8 *config, u8 *cb)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
26462306a36Sopenharmony_ci	int i;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	for (i = 0; i < t_params->count; i++) {
26762306a36Sopenharmony_ci		if (*frequency > t_params->ranges[i].limit)
26862306a36Sopenharmony_ci			continue;
26962306a36Sopenharmony_ci		break;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci	if (i == t_params->count) {
27262306a36Sopenharmony_ci		tuner_dbg("frequency out of range (%d > %d)\n",
27362306a36Sopenharmony_ci			  *frequency, t_params->ranges[i - 1].limit);
27462306a36Sopenharmony_ci		*frequency = t_params->ranges[--i].limit;
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci	*config = t_params->ranges[i].config;
27762306a36Sopenharmony_ci	*cb     = t_params->ranges[i].cb;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	tuner_dbg("freq = %d.%02d (%d), range = %d, config = 0x%02x, cb = 0x%02x\n",
28062306a36Sopenharmony_ci		  *frequency / 16, *frequency % 16 * 100 / 16, *frequency,
28162306a36Sopenharmony_ci		  i, *config, *cb);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	return i;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci/* ---------------------------------------------------------------------- */
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic void simple_set_rf_input(struct dvb_frontend *fe,
28962306a36Sopenharmony_ci				u8 *config, u8 *cb, unsigned int rf)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	switch (priv->type) {
29462306a36Sopenharmony_ci	case TUNER_PHILIPS_TUV1236D:
29562306a36Sopenharmony_ci		switch (rf) {
29662306a36Sopenharmony_ci		case 1:
29762306a36Sopenharmony_ci			*cb |= 0x08;
29862306a36Sopenharmony_ci			break;
29962306a36Sopenharmony_ci		default:
30062306a36Sopenharmony_ci			*cb &= ~0x08;
30162306a36Sopenharmony_ci			break;
30262306a36Sopenharmony_ci		}
30362306a36Sopenharmony_ci		break;
30462306a36Sopenharmony_ci	case TUNER_PHILIPS_FCV1236D:
30562306a36Sopenharmony_ci		switch (rf) {
30662306a36Sopenharmony_ci		case 1:
30762306a36Sopenharmony_ci			*cb |= 0x01;
30862306a36Sopenharmony_ci			break;
30962306a36Sopenharmony_ci		default:
31062306a36Sopenharmony_ci			*cb &= ~0x01;
31162306a36Sopenharmony_ci			break;
31262306a36Sopenharmony_ci		}
31362306a36Sopenharmony_ci		break;
31462306a36Sopenharmony_ci	default:
31562306a36Sopenharmony_ci		break;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic int simple_std_setup(struct dvb_frontend *fe,
32062306a36Sopenharmony_ci			    struct analog_parameters *params,
32162306a36Sopenharmony_ci			    u8 *config, u8 *cb)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
32462306a36Sopenharmony_ci	int rc;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/* tv norm specific stuff for multi-norm tuners */
32762306a36Sopenharmony_ci	switch (priv->type) {
32862306a36Sopenharmony_ci	case TUNER_PHILIPS_SECAM: /* FI1216MF */
32962306a36Sopenharmony_ci		/* 0x01 -> ??? no change ??? */
33062306a36Sopenharmony_ci		/* 0x02 -> PAL BDGHI / SECAM L */
33162306a36Sopenharmony_ci		/* 0x04 -> ??? PAL others / SECAM others ??? */
33262306a36Sopenharmony_ci		*cb &= ~0x03;
33362306a36Sopenharmony_ci		if (params->std & V4L2_STD_SECAM_L)
33462306a36Sopenharmony_ci			/* also valid for V4L2_STD_SECAM */
33562306a36Sopenharmony_ci			*cb |= PHILIPS_MF_SET_STD_L;
33662306a36Sopenharmony_ci		else if (params->std & V4L2_STD_SECAM_LC)
33762306a36Sopenharmony_ci			*cb |= PHILIPS_MF_SET_STD_LC;
33862306a36Sopenharmony_ci		else /* V4L2_STD_B|V4L2_STD_GH */
33962306a36Sopenharmony_ci			*cb |= PHILIPS_MF_SET_STD_BG;
34062306a36Sopenharmony_ci		break;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	case TUNER_TEMIC_4046FM5:
34362306a36Sopenharmony_ci		*cb &= ~0x0f;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci		if (params->std & V4L2_STD_PAL_BG) {
34662306a36Sopenharmony_ci			*cb |= TEMIC_SET_PAL_BG;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		} else if (params->std & V4L2_STD_PAL_I) {
34962306a36Sopenharmony_ci			*cb |= TEMIC_SET_PAL_I;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		} else if (params->std & V4L2_STD_PAL_DK) {
35262306a36Sopenharmony_ci			*cb |= TEMIC_SET_PAL_DK;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci		} else if (params->std & V4L2_STD_SECAM_L) {
35562306a36Sopenharmony_ci			*cb |= TEMIC_SET_PAL_L;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		}
35862306a36Sopenharmony_ci		break;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	case TUNER_PHILIPS_FQ1216ME:
36162306a36Sopenharmony_ci		*cb &= ~0x0f;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
36462306a36Sopenharmony_ci			*cb |= PHILIPS_SET_PAL_BGDK;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci		} else if (params->std & V4L2_STD_PAL_I) {
36762306a36Sopenharmony_ci			*cb |= PHILIPS_SET_PAL_I;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci		} else if (params->std & V4L2_STD_SECAM_L) {
37062306a36Sopenharmony_ci			*cb |= PHILIPS_SET_PAL_L;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		}
37362306a36Sopenharmony_ci		break;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	case TUNER_PHILIPS_FCV1236D:
37662306a36Sopenharmony_ci		/* 0x00 -> ATSC antenna input 1 */
37762306a36Sopenharmony_ci		/* 0x01 -> ATSC antenna input 2 */
37862306a36Sopenharmony_ci		/* 0x02 -> NTSC antenna input 1 */
37962306a36Sopenharmony_ci		/* 0x03 -> NTSC antenna input 2 */
38062306a36Sopenharmony_ci		*cb &= ~0x03;
38162306a36Sopenharmony_ci		if (!(params->std & V4L2_STD_ATSC))
38262306a36Sopenharmony_ci			*cb |= 2;
38362306a36Sopenharmony_ci		break;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	case TUNER_MICROTUNE_4042FI5:
38662306a36Sopenharmony_ci		/* Set the charge pump for fast tuning */
38762306a36Sopenharmony_ci		*config |= TUNER_CHARGE_PUMP;
38862306a36Sopenharmony_ci		break;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	case TUNER_PHILIPS_TUV1236D:
39162306a36Sopenharmony_ci	{
39262306a36Sopenharmony_ci		struct tuner_i2c_props i2c = priv->i2c_props;
39362306a36Sopenharmony_ci		/* 0x40 -> ATSC antenna input 1 */
39462306a36Sopenharmony_ci		/* 0x48 -> ATSC antenna input 2 */
39562306a36Sopenharmony_ci		/* 0x00 -> NTSC antenna input 1 */
39662306a36Sopenharmony_ci		/* 0x08 -> NTSC antenna input 2 */
39762306a36Sopenharmony_ci		u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00};
39862306a36Sopenharmony_ci		*cb &= ~0x40;
39962306a36Sopenharmony_ci		if (params->std & V4L2_STD_ATSC) {
40062306a36Sopenharmony_ci			*cb |= 0x40;
40162306a36Sopenharmony_ci			buffer[1] = 0x04;
40262306a36Sopenharmony_ci		}
40362306a36Sopenharmony_ci		/* set to the correct mode (analog or digital) */
40462306a36Sopenharmony_ci		i2c.addr = 0x0a;
40562306a36Sopenharmony_ci		rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2);
40662306a36Sopenharmony_ci		if (2 != rc)
40762306a36Sopenharmony_ci			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",
40862306a36Sopenharmony_ci				   rc);
40962306a36Sopenharmony_ci		rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2);
41062306a36Sopenharmony_ci		if (2 != rc)
41162306a36Sopenharmony_ci			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",
41262306a36Sopenharmony_ci				   rc);
41362306a36Sopenharmony_ci		break;
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci	if (atv_input[priv->nr])
41762306a36Sopenharmony_ci		simple_set_rf_input(fe, config, cb, atv_input[priv->nr]);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return 0;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
42562306a36Sopenharmony_ci	int rc;
42662306a36Sopenharmony_ci	u8 buffer[2];
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	buffer[0] = (config & ~0x38) | 0x18;
42962306a36Sopenharmony_ci	buffer[1] = aux;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
43462306a36Sopenharmony_ci	if (2 != rc)
43562306a36Sopenharmony_ci		tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	return rc == 2 ? 0 : rc;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
44162306a36Sopenharmony_ci			    u16 div, u8 config, u8 cb)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
44462306a36Sopenharmony_ci	int rc;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	switch (priv->type) {
44762306a36Sopenharmony_ci	case TUNER_LG_TDVS_H06XF:
44862306a36Sopenharmony_ci		simple_set_aux_byte(fe, config, 0x20);
44962306a36Sopenharmony_ci		break;
45062306a36Sopenharmony_ci	case TUNER_PHILIPS_FQ1216LME_MK3:
45162306a36Sopenharmony_ci		simple_set_aux_byte(fe, config, 0x60); /* External AGC */
45262306a36Sopenharmony_ci		break;
45362306a36Sopenharmony_ci	case TUNER_MICROTUNE_4042FI5:
45462306a36Sopenharmony_ci	{
45562306a36Sopenharmony_ci		/* FIXME - this may also work for other tuners */
45662306a36Sopenharmony_ci		unsigned long timeout = jiffies + msecs_to_jiffies(1);
45762306a36Sopenharmony_ci		u8 status_byte = 0;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		/* Wait until the PLL locks */
46062306a36Sopenharmony_ci		for (;;) {
46162306a36Sopenharmony_ci			if (time_after(jiffies, timeout))
46262306a36Sopenharmony_ci				return 0;
46362306a36Sopenharmony_ci			rc = tuner_i2c_xfer_recv(&priv->i2c_props,
46462306a36Sopenharmony_ci						 &status_byte, 1);
46562306a36Sopenharmony_ci			if (1 != rc) {
46662306a36Sopenharmony_ci				tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",
46762306a36Sopenharmony_ci					   rc);
46862306a36Sopenharmony_ci				break;
46962306a36Sopenharmony_ci			}
47062306a36Sopenharmony_ci			if (status_byte & TUNER_PLL_LOCKED)
47162306a36Sopenharmony_ci				break;
47262306a36Sopenharmony_ci			udelay(10);
47362306a36Sopenharmony_ci		}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		/* Set the charge pump for optimized phase noise figure */
47662306a36Sopenharmony_ci		config &= ~TUNER_CHARGE_PUMP;
47762306a36Sopenharmony_ci		buffer[0] = (div>>8) & 0x7f;
47862306a36Sopenharmony_ci		buffer[1] = div      & 0xff;
47962306a36Sopenharmony_ci		buffer[2] = config;
48062306a36Sopenharmony_ci		buffer[3] = cb;
48162306a36Sopenharmony_ci		tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
48262306a36Sopenharmony_ci			  buffer[0], buffer[1], buffer[2], buffer[3]);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
48562306a36Sopenharmony_ci		if (4 != rc)
48662306a36Sopenharmony_ci			tuner_warn("i2c i/o error: rc == %d (should be 4)\n",
48762306a36Sopenharmony_ci				   rc);
48862306a36Sopenharmony_ci		break;
48962306a36Sopenharmony_ci	}
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	return 0;
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	switch (priv->type) {
50062306a36Sopenharmony_ci	case TUNER_TENA_9533_DI:
50162306a36Sopenharmony_ci	case TUNER_YMEC_TVF_5533MF:
50262306a36Sopenharmony_ci		tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n");
50362306a36Sopenharmony_ci		return -EINVAL;
50462306a36Sopenharmony_ci	case TUNER_PHILIPS_FM1216ME_MK3:
50562306a36Sopenharmony_ci	case TUNER_PHILIPS_FM1236_MK3:
50662306a36Sopenharmony_ci	case TUNER_PHILIPS_FMD1216ME_MK3:
50762306a36Sopenharmony_ci	case TUNER_PHILIPS_FMD1216MEX_MK3:
50862306a36Sopenharmony_ci	case TUNER_LG_NTSC_TAPE:
50962306a36Sopenharmony_ci	case TUNER_PHILIPS_FM1256_IH3:
51062306a36Sopenharmony_ci	case TUNER_TCL_MF02GIP_5N:
51162306a36Sopenharmony_ci		buffer[3] = 0x19;
51262306a36Sopenharmony_ci		break;
51362306a36Sopenharmony_ci	case TUNER_PHILIPS_FM1216MK5:
51462306a36Sopenharmony_ci		buffer[2] = 0x88;
51562306a36Sopenharmony_ci		buffer[3] = 0x09;
51662306a36Sopenharmony_ci		break;
51762306a36Sopenharmony_ci	case TUNER_TNF_5335MF:
51862306a36Sopenharmony_ci		buffer[3] = 0x11;
51962306a36Sopenharmony_ci		break;
52062306a36Sopenharmony_ci	case TUNER_LG_PAL_FM:
52162306a36Sopenharmony_ci		buffer[3] = 0xa5;
52262306a36Sopenharmony_ci		break;
52362306a36Sopenharmony_ci	case TUNER_THOMSON_DTT761X:
52462306a36Sopenharmony_ci		buffer[3] = 0x39;
52562306a36Sopenharmony_ci		break;
52662306a36Sopenharmony_ci	case TUNER_PHILIPS_FQ1216LME_MK3:
52762306a36Sopenharmony_ci	case TUNER_PHILIPS_FQ1236_MK5:
52862306a36Sopenharmony_ci		tuner_err("This tuner doesn't have FM\n");
52962306a36Sopenharmony_ci		/* Set the low band for sanity, since it covers 88-108 MHz */
53062306a36Sopenharmony_ci		buffer[3] = 0x01;
53162306a36Sopenharmony_ci		break;
53262306a36Sopenharmony_ci	case TUNER_MICROTUNE_4049FM5:
53362306a36Sopenharmony_ci	default:
53462306a36Sopenharmony_ci		buffer[3] = 0xa4;
53562306a36Sopenharmony_ci		break;
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	return 0;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci/* ---------------------------------------------------------------------- */
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic int simple_set_tv_freq(struct dvb_frontend *fe,
54462306a36Sopenharmony_ci			      struct analog_parameters *params)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
54762306a36Sopenharmony_ci	u8 config, cb;
54862306a36Sopenharmony_ci	u16 div;
54962306a36Sopenharmony_ci	u8 buffer[4];
55062306a36Sopenharmony_ci	int rc, IFPCoff, i;
55162306a36Sopenharmony_ci	enum param_type desired_type;
55262306a36Sopenharmony_ci	struct tuner_params *t_params;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	/* IFPCoff = Video Intermediate Frequency - Vif:
55562306a36Sopenharmony_ci		940  =16*58.75  NTSC/J (Japan)
55662306a36Sopenharmony_ci		732  =16*45.75  M/N STD
55762306a36Sopenharmony_ci		704  =16*44     ATSC (at DVB code)
55862306a36Sopenharmony_ci		632  =16*39.50  I U.K.
55962306a36Sopenharmony_ci		622.4=16*38.90  B/G D/K I, L STD
56062306a36Sopenharmony_ci		592  =16*37.00  D China
56162306a36Sopenharmony_ci		590  =16.36.875 B Australia
56262306a36Sopenharmony_ci		543.2=16*33.95  L' STD
56362306a36Sopenharmony_ci		171.2=16*10.70  FM Radio (at set_radio_freq)
56462306a36Sopenharmony_ci	*/
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	if (params->std == V4L2_STD_NTSC_M_JP) {
56762306a36Sopenharmony_ci		IFPCoff      = 940;
56862306a36Sopenharmony_ci		desired_type = TUNER_PARAM_TYPE_NTSC;
56962306a36Sopenharmony_ci	} else if ((params->std & V4L2_STD_MN) &&
57062306a36Sopenharmony_ci		  !(params->std & ~V4L2_STD_MN)) {
57162306a36Sopenharmony_ci		IFPCoff      = 732;
57262306a36Sopenharmony_ci		desired_type = TUNER_PARAM_TYPE_NTSC;
57362306a36Sopenharmony_ci	} else if (params->std == V4L2_STD_SECAM_LC) {
57462306a36Sopenharmony_ci		IFPCoff      = 543;
57562306a36Sopenharmony_ci		desired_type = TUNER_PARAM_TYPE_SECAM;
57662306a36Sopenharmony_ci	} else {
57762306a36Sopenharmony_ci		IFPCoff      = 623;
57862306a36Sopenharmony_ci		desired_type = TUNER_PARAM_TYPE_PAL;
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	t_params = simple_tuner_params(fe, desired_type);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	i = simple_config_lookup(fe, t_params, &params->frequency,
58462306a36Sopenharmony_ci				 &config, &cb);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	div = params->frequency + IFPCoff + offset;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
58962306a36Sopenharmony_ci		  params->frequency / 16, params->frequency % 16 * 100 / 16,
59062306a36Sopenharmony_ci		  IFPCoff / 16, IFPCoff % 16 * 100 / 16,
59162306a36Sopenharmony_ci		  offset / 16, offset % 16 * 100 / 16, div);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	/* tv norm specific stuff for multi-norm tuners */
59462306a36Sopenharmony_ci	simple_std_setup(fe, params, &config, &cb);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
59762306a36Sopenharmony_ci		buffer[0] = config;
59862306a36Sopenharmony_ci		buffer[1] = cb;
59962306a36Sopenharmony_ci		buffer[2] = (div>>8) & 0x7f;
60062306a36Sopenharmony_ci		buffer[3] = div      & 0xff;
60162306a36Sopenharmony_ci	} else {
60262306a36Sopenharmony_ci		buffer[0] = (div>>8) & 0x7f;
60362306a36Sopenharmony_ci		buffer[1] = div      & 0xff;
60462306a36Sopenharmony_ci		buffer[2] = config;
60562306a36Sopenharmony_ci		buffer[3] = cb;
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci	priv->last_div = div;
60862306a36Sopenharmony_ci	if (t_params->has_tda9887) {
60962306a36Sopenharmony_ci		struct v4l2_priv_tun_config tda9887_cfg;
61062306a36Sopenharmony_ci		int tda_config = 0;
61162306a36Sopenharmony_ci		int is_secam_l = (params->std & (V4L2_STD_SECAM_L |
61262306a36Sopenharmony_ci						 V4L2_STD_SECAM_LC)) &&
61362306a36Sopenharmony_ci			!(params->std & ~(V4L2_STD_SECAM_L |
61462306a36Sopenharmony_ci					  V4L2_STD_SECAM_LC));
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci		tda9887_cfg.tuner = TUNER_TDA9887;
61762306a36Sopenharmony_ci		tda9887_cfg.priv  = &tda_config;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		if (params->std == V4L2_STD_SECAM_LC) {
62062306a36Sopenharmony_ci			if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
62162306a36Sopenharmony_ci				tda_config |= TDA9887_PORT1_ACTIVE;
62262306a36Sopenharmony_ci			if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
62362306a36Sopenharmony_ci				tda_config |= TDA9887_PORT2_ACTIVE;
62462306a36Sopenharmony_ci		} else {
62562306a36Sopenharmony_ci			if (t_params->port1_active)
62662306a36Sopenharmony_ci				tda_config |= TDA9887_PORT1_ACTIVE;
62762306a36Sopenharmony_ci			if (t_params->port2_active)
62862306a36Sopenharmony_ci				tda_config |= TDA9887_PORT2_ACTIVE;
62962306a36Sopenharmony_ci		}
63062306a36Sopenharmony_ci		if (t_params->intercarrier_mode)
63162306a36Sopenharmony_ci			tda_config |= TDA9887_INTERCARRIER;
63262306a36Sopenharmony_ci		if (is_secam_l) {
63362306a36Sopenharmony_ci			if (i == 0 && t_params->default_top_secam_low)
63462306a36Sopenharmony_ci				tda_config |= TDA9887_TOP(t_params->default_top_secam_low);
63562306a36Sopenharmony_ci			else if (i == 1 && t_params->default_top_secam_mid)
63662306a36Sopenharmony_ci				tda_config |= TDA9887_TOP(t_params->default_top_secam_mid);
63762306a36Sopenharmony_ci			else if (t_params->default_top_secam_high)
63862306a36Sopenharmony_ci				tda_config |= TDA9887_TOP(t_params->default_top_secam_high);
63962306a36Sopenharmony_ci		} else {
64062306a36Sopenharmony_ci			if (i == 0 && t_params->default_top_low)
64162306a36Sopenharmony_ci				tda_config |= TDA9887_TOP(t_params->default_top_low);
64262306a36Sopenharmony_ci			else if (i == 1 && t_params->default_top_mid)
64362306a36Sopenharmony_ci				tda_config |= TDA9887_TOP(t_params->default_top_mid);
64462306a36Sopenharmony_ci			else if (t_params->default_top_high)
64562306a36Sopenharmony_ci				tda_config |= TDA9887_TOP(t_params->default_top_high);
64662306a36Sopenharmony_ci		}
64762306a36Sopenharmony_ci		if (t_params->default_pll_gating_18)
64862306a36Sopenharmony_ci			tda_config |= TDA9887_GATING_18;
64962306a36Sopenharmony_ci		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
65062306a36Sopenharmony_ci				    &tda9887_cfg);
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
65362306a36Sopenharmony_ci		  buffer[0], buffer[1], buffer[2], buffer[3]);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
65662306a36Sopenharmony_ci	if (4 != rc)
65762306a36Sopenharmony_ci		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	simple_post_tune(fe, &buffer[0], div, config, cb);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	return 0;
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic int simple_set_radio_freq(struct dvb_frontend *fe,
66562306a36Sopenharmony_ci				 struct analog_parameters *params)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	struct tunertype *tun;
66862306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
66962306a36Sopenharmony_ci	u8 buffer[4];
67062306a36Sopenharmony_ci	u16 div;
67162306a36Sopenharmony_ci	int rc, j;
67262306a36Sopenharmony_ci	struct tuner_params *t_params;
67362306a36Sopenharmony_ci	unsigned int freq = params->frequency;
67462306a36Sopenharmony_ci	bool mono = params->audmode == V4L2_TUNER_MODE_MONO;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	tun = priv->tun;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	for (j = tun->count-1; j > 0; j--)
67962306a36Sopenharmony_ci		if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO)
68062306a36Sopenharmony_ci			break;
68162306a36Sopenharmony_ci	/* default t_params (j=0) will be used if desired type wasn't found */
68262306a36Sopenharmony_ci	t_params = &tun->params[j];
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* Select Radio 1st IF used */
68562306a36Sopenharmony_ci	switch (t_params->radio_if) {
68662306a36Sopenharmony_ci	case 0: /* 10.7 MHz */
68762306a36Sopenharmony_ci		freq += (unsigned int)(10.7*16000);
68862306a36Sopenharmony_ci		break;
68962306a36Sopenharmony_ci	case 1: /* 33.3 MHz */
69062306a36Sopenharmony_ci		freq += (unsigned int)(33.3*16000);
69162306a36Sopenharmony_ci		break;
69262306a36Sopenharmony_ci	case 2: /* 41.3 MHz */
69362306a36Sopenharmony_ci		freq += (unsigned int)(41.3*16000);
69462306a36Sopenharmony_ci		break;
69562306a36Sopenharmony_ci	default:
69662306a36Sopenharmony_ci		tuner_warn("Unsupported radio_if value %d\n",
69762306a36Sopenharmony_ci			   t_params->radio_if);
69862306a36Sopenharmony_ci		return 0;
69962306a36Sopenharmony_ci	}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
70262306a36Sopenharmony_ci		    TUNER_RATIO_SELECT_50; /* 50 kHz step */
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	/* Bandswitch byte */
70562306a36Sopenharmony_ci	if (simple_radio_bandswitch(fe, &buffer[0]))
70662306a36Sopenharmony_ci		return 0;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
70962306a36Sopenharmony_ci	   freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
71062306a36Sopenharmony_ci	   freq * (1/800) */
71162306a36Sopenharmony_ci	div = (freq + 400) / 800;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
71462306a36Sopenharmony_ci		buffer[0] = buffer[2];
71562306a36Sopenharmony_ci		buffer[1] = buffer[3];
71662306a36Sopenharmony_ci		buffer[2] = (div>>8) & 0x7f;
71762306a36Sopenharmony_ci		buffer[3] = div      & 0xff;
71862306a36Sopenharmony_ci	} else {
71962306a36Sopenharmony_ci		buffer[0] = (div>>8) & 0x7f;
72062306a36Sopenharmony_ci		buffer[1] = div      & 0xff;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
72462306a36Sopenharmony_ci	       buffer[0], buffer[1], buffer[2], buffer[3]);
72562306a36Sopenharmony_ci	priv->last_div = div;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	if (t_params->has_tda9887) {
72862306a36Sopenharmony_ci		int config = 0;
72962306a36Sopenharmony_ci		struct v4l2_priv_tun_config tda9887_cfg;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci		tda9887_cfg.tuner = TUNER_TDA9887;
73262306a36Sopenharmony_ci		tda9887_cfg.priv = &config;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci		if (t_params->port1_active &&
73562306a36Sopenharmony_ci		    !t_params->port1_fm_high_sensitivity)
73662306a36Sopenharmony_ci			config |= TDA9887_PORT1_ACTIVE;
73762306a36Sopenharmony_ci		if (t_params->port2_active &&
73862306a36Sopenharmony_ci		    !t_params->port2_fm_high_sensitivity)
73962306a36Sopenharmony_ci			config |= TDA9887_PORT2_ACTIVE;
74062306a36Sopenharmony_ci		if (t_params->intercarrier_mode)
74162306a36Sopenharmony_ci			config |= TDA9887_INTERCARRIER;
74262306a36Sopenharmony_ci		if (t_params->port1_set_for_fm_mono && mono)
74362306a36Sopenharmony_ci			config &= ~TDA9887_PORT1_ACTIVE;
74462306a36Sopenharmony_ci		if (t_params->fm_gain_normal)
74562306a36Sopenharmony_ci			config |= TDA9887_GAIN_NORMAL;
74662306a36Sopenharmony_ci		if (t_params->radio_if == 2)
74762306a36Sopenharmony_ci			config |= TDA9887_RIF_41_3;
74862306a36Sopenharmony_ci		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
74962306a36Sopenharmony_ci				    &tda9887_cfg);
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
75262306a36Sopenharmony_ci	if (4 != rc)
75362306a36Sopenharmony_ci		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	/* Write AUX byte */
75662306a36Sopenharmony_ci	switch (priv->type) {
75762306a36Sopenharmony_ci	case TUNER_PHILIPS_FM1216ME_MK3:
75862306a36Sopenharmony_ci		buffer[2] = 0x98;
75962306a36Sopenharmony_ci		buffer[3] = 0x20; /* set TOP AGC */
76062306a36Sopenharmony_ci		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
76162306a36Sopenharmony_ci		if (4 != rc)
76262306a36Sopenharmony_ci			tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
76362306a36Sopenharmony_ci		break;
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	return 0;
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cistatic int simple_set_params(struct dvb_frontend *fe,
77062306a36Sopenharmony_ci			     struct analog_parameters *params)
77162306a36Sopenharmony_ci{
77262306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
77362306a36Sopenharmony_ci	int ret = -EINVAL;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	if (priv->i2c_props.adap == NULL)
77662306a36Sopenharmony_ci		return -EINVAL;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	switch (params->mode) {
77962306a36Sopenharmony_ci	case V4L2_TUNER_RADIO:
78062306a36Sopenharmony_ci		priv->radio_mode = true;
78162306a36Sopenharmony_ci		ret = simple_set_radio_freq(fe, params);
78262306a36Sopenharmony_ci		priv->frequency = params->frequency * 125 / 2;
78362306a36Sopenharmony_ci		break;
78462306a36Sopenharmony_ci	case V4L2_TUNER_ANALOG_TV:
78562306a36Sopenharmony_ci	case V4L2_TUNER_DIGITAL_TV:
78662306a36Sopenharmony_ci		priv->radio_mode = false;
78762306a36Sopenharmony_ci		ret = simple_set_tv_freq(fe, params);
78862306a36Sopenharmony_ci		priv->frequency = params->frequency * 62500;
78962306a36Sopenharmony_ci		break;
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci	priv->bandwidth = 0;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	return ret;
79462306a36Sopenharmony_ci}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_cistatic void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
79762306a36Sopenharmony_ci			   const u32 delsys,
79862306a36Sopenharmony_ci			   const u32 frequency,
79962306a36Sopenharmony_ci			   const u32 bandwidth)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	switch (priv->type) {
80462306a36Sopenharmony_ci	case TUNER_PHILIPS_FMD1216ME_MK3:
80562306a36Sopenharmony_ci	case TUNER_PHILIPS_FMD1216MEX_MK3:
80662306a36Sopenharmony_ci		if (bandwidth == 8000000 &&
80762306a36Sopenharmony_ci		    frequency >= 158870000)
80862306a36Sopenharmony_ci			buf[3] |= 0x08;
80962306a36Sopenharmony_ci		break;
81062306a36Sopenharmony_ci	case TUNER_PHILIPS_TD1316:
81162306a36Sopenharmony_ci		/* determine band */
81262306a36Sopenharmony_ci		buf[3] |= (frequency < 161000000) ? 1 :
81362306a36Sopenharmony_ci			  (frequency < 444000000) ? 2 : 4;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci		/* setup PLL filter */
81662306a36Sopenharmony_ci		if (bandwidth == 8000000)
81762306a36Sopenharmony_ci			buf[3] |= 1 << 3;
81862306a36Sopenharmony_ci		break;
81962306a36Sopenharmony_ci	case TUNER_PHILIPS_TUV1236D:
82062306a36Sopenharmony_ci	case TUNER_PHILIPS_FCV1236D:
82162306a36Sopenharmony_ci	{
82262306a36Sopenharmony_ci		unsigned int new_rf;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci		if (dtv_input[priv->nr])
82562306a36Sopenharmony_ci			new_rf = dtv_input[priv->nr];
82662306a36Sopenharmony_ci		else
82762306a36Sopenharmony_ci			switch (delsys) {
82862306a36Sopenharmony_ci			case SYS_DVBC_ANNEX_B:
82962306a36Sopenharmony_ci				new_rf = 1;
83062306a36Sopenharmony_ci				break;
83162306a36Sopenharmony_ci			case SYS_ATSC:
83262306a36Sopenharmony_ci			default:
83362306a36Sopenharmony_ci				new_rf = 0;
83462306a36Sopenharmony_ci				break;
83562306a36Sopenharmony_ci			}
83662306a36Sopenharmony_ci		simple_set_rf_input(fe, &buf[2], &buf[3], new_rf);
83762306a36Sopenharmony_ci		break;
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci	default:
84062306a36Sopenharmony_ci		break;
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_cistatic u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
84562306a36Sopenharmony_ci				const u32 delsys,
84662306a36Sopenharmony_ci				const u32 freq,
84762306a36Sopenharmony_ci				const u32 bw)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	/* This function returns the tuned frequency on success, 0 on error */
85062306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
85162306a36Sopenharmony_ci	struct tunertype *tun = priv->tun;
85262306a36Sopenharmony_ci	struct tuner_params *t_params;
85362306a36Sopenharmony_ci	u8 config, cb;
85462306a36Sopenharmony_ci	u32 div;
85562306a36Sopenharmony_ci	int ret;
85662306a36Sopenharmony_ci	u32 frequency = freq / 62500;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	if (!tun->stepsize) {
85962306a36Sopenharmony_ci		/* tuner-core was loaded before the digital tuner was
86062306a36Sopenharmony_ci		 * configured and somehow picked the wrong tuner type */
86162306a36Sopenharmony_ci		tuner_err("attempt to treat tuner %d (%s) as digital tuner without stepsize defined.\n",
86262306a36Sopenharmony_ci			  priv->type, priv->tun->name);
86362306a36Sopenharmony_ci		return 0; /* failure */
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
86762306a36Sopenharmony_ci	ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
86862306a36Sopenharmony_ci	if (ret < 0)
86962306a36Sopenharmony_ci		return 0; /* failure */
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	div = ((frequency + t_params->iffreq) * 62500 + offset +
87262306a36Sopenharmony_ci	       tun->stepsize/2) / tun->stepsize;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	buf[0] = div >> 8;
87562306a36Sopenharmony_ci	buf[1] = div & 0xff;
87662306a36Sopenharmony_ci	buf[2] = config;
87762306a36Sopenharmony_ci	buf[3] = cb;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	simple_set_dvb(fe, buf, delsys, freq, bw);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
88262306a36Sopenharmony_ci		  tun->name, div, buf[0], buf[1], buf[2], buf[3]);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	/* calculate the frequency we set it to */
88562306a36Sopenharmony_ci	return (div * tun->stepsize) - t_params->iffreq;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_cistatic int simple_dvb_calc_regs(struct dvb_frontend *fe,
88962306a36Sopenharmony_ci				u8 *buf, int buf_len)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
89262306a36Sopenharmony_ci	u32 delsys = c->delivery_system;
89362306a36Sopenharmony_ci	u32 bw = c->bandwidth_hz;
89462306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
89562306a36Sopenharmony_ci	u32 frequency;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	if (buf_len < 5)
89862306a36Sopenharmony_ci		return -EINVAL;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	frequency = simple_dvb_configure(fe, buf+1, delsys, c->frequency, bw);
90162306a36Sopenharmony_ci	if (frequency == 0)
90262306a36Sopenharmony_ci		return -EINVAL;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	buf[0] = priv->i2c_props.addr;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	priv->frequency = frequency;
90762306a36Sopenharmony_ci	priv->bandwidth = c->bandwidth_hz;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	return 5;
91062306a36Sopenharmony_ci}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_cistatic int simple_dvb_set_params(struct dvb_frontend *fe)
91362306a36Sopenharmony_ci{
91462306a36Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
91562306a36Sopenharmony_ci	u32 delsys = c->delivery_system;
91662306a36Sopenharmony_ci	u32 bw = c->bandwidth_hz;
91762306a36Sopenharmony_ci	u32 freq = c->frequency;
91862306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
91962306a36Sopenharmony_ci	u32 frequency;
92062306a36Sopenharmony_ci	u32 prev_freq, prev_bw;
92162306a36Sopenharmony_ci	int ret;
92262306a36Sopenharmony_ci	u8 buf[5];
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	if (priv->i2c_props.adap == NULL)
92562306a36Sopenharmony_ci		return -EINVAL;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	prev_freq = priv->frequency;
92862306a36Sopenharmony_ci	prev_bw   = priv->bandwidth;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	frequency = simple_dvb_configure(fe, buf+1, delsys, freq, bw);
93162306a36Sopenharmony_ci	if (frequency == 0)
93262306a36Sopenharmony_ci		return -EINVAL;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	buf[0] = priv->i2c_props.addr;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	priv->frequency = frequency;
93762306a36Sopenharmony_ci	priv->bandwidth = bw;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	/* put analog demod in standby when tuning digital */
94062306a36Sopenharmony_ci	if (fe->ops.analog_ops.standby)
94162306a36Sopenharmony_ci		fe->ops.analog_ops.standby(fe);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
94462306a36Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	/* buf[0] contains the i2c address, but *
94762306a36Sopenharmony_ci	 * we already have it in i2c_props.addr */
94862306a36Sopenharmony_ci	ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4);
94962306a36Sopenharmony_ci	if (ret != 4)
95062306a36Sopenharmony_ci		goto fail;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	return 0;
95362306a36Sopenharmony_cifail:
95462306a36Sopenharmony_ci	/* calc_regs sets frequency and bandwidth. if we failed, unset them */
95562306a36Sopenharmony_ci	priv->frequency = prev_freq;
95662306a36Sopenharmony_ci	priv->bandwidth = prev_bw;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	return ret;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cistatic int simple_init(struct dvb_frontend *fe)
96262306a36Sopenharmony_ci{
96362306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	if (priv->i2c_props.adap == NULL)
96662306a36Sopenharmony_ci		return -EINVAL;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	if (priv->tun->initdata) {
96962306a36Sopenharmony_ci		int ret;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci		if (fe->ops.i2c_gate_ctrl)
97262306a36Sopenharmony_ci			fe->ops.i2c_gate_ctrl(fe, 1);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci		ret = tuner_i2c_xfer_send(&priv->i2c_props,
97562306a36Sopenharmony_ci					  priv->tun->initdata + 1,
97662306a36Sopenharmony_ci					  priv->tun->initdata[0]);
97762306a36Sopenharmony_ci		if (ret != priv->tun->initdata[0])
97862306a36Sopenharmony_ci			return ret;
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	return 0;
98262306a36Sopenharmony_ci}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_cistatic int simple_sleep(struct dvb_frontend *fe)
98562306a36Sopenharmony_ci{
98662306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	if (priv->i2c_props.adap == NULL)
98962306a36Sopenharmony_ci		return -EINVAL;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	if (priv->tun->sleepdata) {
99262306a36Sopenharmony_ci		int ret;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci		if (fe->ops.i2c_gate_ctrl)
99562306a36Sopenharmony_ci			fe->ops.i2c_gate_ctrl(fe, 1);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci		ret = tuner_i2c_xfer_send(&priv->i2c_props,
99862306a36Sopenharmony_ci					  priv->tun->sleepdata + 1,
99962306a36Sopenharmony_ci					  priv->tun->sleepdata[0]);
100062306a36Sopenharmony_ci		if (ret != priv->tun->sleepdata[0])
100162306a36Sopenharmony_ci			return ret;
100262306a36Sopenharmony_ci	}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	return 0;
100562306a36Sopenharmony_ci}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_cistatic void simple_release(struct dvb_frontend *fe)
100862306a36Sopenharmony_ci{
100962306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	mutex_lock(&tuner_simple_list_mutex);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	if (priv)
101462306a36Sopenharmony_ci		hybrid_tuner_release_state(priv);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	mutex_unlock(&tuner_simple_list_mutex);
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	fe->tuner_priv = NULL;
101962306a36Sopenharmony_ci}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_cistatic int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency)
102262306a36Sopenharmony_ci{
102362306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
102462306a36Sopenharmony_ci	*frequency = priv->frequency;
102562306a36Sopenharmony_ci	return 0;
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_cistatic int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
102962306a36Sopenharmony_ci{
103062306a36Sopenharmony_ci	struct tuner_simple_priv *priv = fe->tuner_priv;
103162306a36Sopenharmony_ci	*bandwidth = priv->bandwidth;
103262306a36Sopenharmony_ci	return 0;
103362306a36Sopenharmony_ci}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_cistatic const struct dvb_tuner_ops simple_tuner_ops = {
103662306a36Sopenharmony_ci	.init              = simple_init,
103762306a36Sopenharmony_ci	.sleep             = simple_sleep,
103862306a36Sopenharmony_ci	.set_analog_params = simple_set_params,
103962306a36Sopenharmony_ci	.set_params        = simple_dvb_set_params,
104062306a36Sopenharmony_ci	.calc_regs         = simple_dvb_calc_regs,
104162306a36Sopenharmony_ci	.release           = simple_release,
104262306a36Sopenharmony_ci	.get_frequency     = simple_get_frequency,
104362306a36Sopenharmony_ci	.get_bandwidth     = simple_get_bandwidth,
104462306a36Sopenharmony_ci	.get_status        = simple_get_status,
104562306a36Sopenharmony_ci	.get_rf_strength   = simple_get_rf_strength,
104662306a36Sopenharmony_ci};
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cistruct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
104962306a36Sopenharmony_ci					 struct i2c_adapter *i2c_adap,
105062306a36Sopenharmony_ci					 u8 i2c_addr,
105162306a36Sopenharmony_ci					 unsigned int type)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	struct tuner_simple_priv *priv = NULL;
105462306a36Sopenharmony_ci	int instance;
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	if (type >= tuner_count) {
105762306a36Sopenharmony_ci		printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n",
105862306a36Sopenharmony_ci		       __func__, type, tuner_count-1);
105962306a36Sopenharmony_ci		return NULL;
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	/* If i2c_adap is set, check that the tuner is at the correct address.
106362306a36Sopenharmony_ci	 * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly
106462306a36Sopenharmony_ci	 * by the digital demod via calc_regs.
106562306a36Sopenharmony_ci	 */
106662306a36Sopenharmony_ci	if (i2c_adap != NULL) {
106762306a36Sopenharmony_ci		u8 b[1];
106862306a36Sopenharmony_ci		struct i2c_msg msg = {
106962306a36Sopenharmony_ci			.addr = i2c_addr, .flags = I2C_M_RD,
107062306a36Sopenharmony_ci			.buf = b, .len = 1,
107162306a36Sopenharmony_ci		};
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci		if (fe->ops.i2c_gate_ctrl)
107462306a36Sopenharmony_ci			fe->ops.i2c_gate_ctrl(fe, 1);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci		if (1 != i2c_transfer(i2c_adap, &msg, 1))
107762306a36Sopenharmony_ci			printk(KERN_WARNING "tuner-simple %d-%04x: unable to probe %s, proceeding anyway.",
107862306a36Sopenharmony_ci			       i2c_adapter_id(i2c_adap), i2c_addr,
107962306a36Sopenharmony_ci			       tuners[type].name);
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci		if (fe->ops.i2c_gate_ctrl)
108262306a36Sopenharmony_ci			fe->ops.i2c_gate_ctrl(fe, 0);
108362306a36Sopenharmony_ci	}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	mutex_lock(&tuner_simple_list_mutex);
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv,
108862306a36Sopenharmony_ci					      hybrid_tuner_instance_list,
108962306a36Sopenharmony_ci					      i2c_adap, i2c_addr,
109062306a36Sopenharmony_ci					      "tuner-simple");
109162306a36Sopenharmony_ci	switch (instance) {
109262306a36Sopenharmony_ci	case 0:
109362306a36Sopenharmony_ci		mutex_unlock(&tuner_simple_list_mutex);
109462306a36Sopenharmony_ci		return NULL;
109562306a36Sopenharmony_ci	case 1:
109662306a36Sopenharmony_ci		fe->tuner_priv = priv;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci		priv->type = type;
109962306a36Sopenharmony_ci		priv->tun  = &tuners[type];
110062306a36Sopenharmony_ci		priv->nr   = simple_devcount++;
110162306a36Sopenharmony_ci		break;
110262306a36Sopenharmony_ci	default:
110362306a36Sopenharmony_ci		fe->tuner_priv = priv;
110462306a36Sopenharmony_ci		break;
110562306a36Sopenharmony_ci	}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	mutex_unlock(&tuner_simple_list_mutex);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	memcpy(&fe->ops.tuner_ops, &simple_tuner_ops,
111062306a36Sopenharmony_ci	       sizeof(struct dvb_tuner_ops));
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	if (type != priv->type)
111362306a36Sopenharmony_ci		tuner_warn("couldn't set type to %d. Using %d (%s) instead\n",
111462306a36Sopenharmony_ci			    type, priv->type, priv->tun->name);
111562306a36Sopenharmony_ci	else
111662306a36Sopenharmony_ci		tuner_info("type set to %d (%s)\n",
111762306a36Sopenharmony_ci			   priv->type, priv->tun->name);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	if ((debug) || ((atv_input[priv->nr] > 0) ||
112062306a36Sopenharmony_ci			(dtv_input[priv->nr] > 0))) {
112162306a36Sopenharmony_ci		if (0 == atv_input[priv->nr])
112262306a36Sopenharmony_ci			tuner_info("tuner %d atv rf input will be autoselected\n",
112362306a36Sopenharmony_ci				   priv->nr);
112462306a36Sopenharmony_ci		else
112562306a36Sopenharmony_ci			tuner_info("tuner %d atv rf input will be set to input %d (insmod option)\n",
112662306a36Sopenharmony_ci				   priv->nr, atv_input[priv->nr]);
112762306a36Sopenharmony_ci		if (0 == dtv_input[priv->nr])
112862306a36Sopenharmony_ci			tuner_info("tuner %d dtv rf input will be autoselected\n",
112962306a36Sopenharmony_ci				   priv->nr);
113062306a36Sopenharmony_ci		else
113162306a36Sopenharmony_ci			tuner_info("tuner %d dtv rf input will be set to input %d (insmod option)\n",
113262306a36Sopenharmony_ci				   priv->nr, dtv_input[priv->nr]);
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	strscpy(fe->ops.tuner_ops.info.name, priv->tun->name,
113662306a36Sopenharmony_ci		sizeof(fe->ops.tuner_ops.info.name));
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	return fe;
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(simple_tuner_attach);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ciMODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");
114362306a36Sopenharmony_ciMODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
114462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1145