/*
* i2c tv tuner chip device driver
* controls all those simple 4-control-bytes style tuners.
*
* This "tuner-simple" module was split apart from the original "tuner" module.
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
#include <media/tuner-types.h>
#include "tuner-i2c.h"
#include "tuner-simple.h"
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
#define TUNER_SIMPLE_MAX 64
static unsigned int simple_devcount;
static int offset;
module_param(offset, int, 0664);
MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner");
static unsigned int atv_input[TUNER_SIMPLE_MAX] = \
{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \
{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
module_param_array(atv_input, int, NULL, 0644);
module_param_array(dtv_input, int, NULL, 0644);
MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect");
MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect");
/* ---------------------------------------------------------------------- */
/* tv standard selection for Temic 4046 FM5
this value takes the low bits of control byte 2
from datasheet Rev.01, Feb.00
standard BG I L L2 D
picture IF 38.9 38.9 38.9 33.95 38.9
sound 1 33.4 32.9 32.4 40.45 32.4
sound 2 33.16
NICAM 33.05 32.348 33.05 33.05
*/
#define TEMIC_SET_PAL_I 0x05
#define TEMIC_SET_PAL_DK 0x09
#define TEMIC_SET_PAL_L 0x0a /* SECAM ? */
#define TEMIC_SET_PAL_L2 0x0b /* change IF ! */
#define TEMIC_SET_PAL_BG 0x0c
/* tv tuner system standard selection for Philips FQ1216ME
this value takes the low bits of control byte 2
from datasheet "1999 Nov 16" (supersedes "1999 Mar 23")
standard BG DK I L L`
picture carrier 38.90 38.90 38.90 38.90 33.95
colour 34.47 34.47 34.47 34.47 38.38
sound 1 33.40 32.40 32.90 32.40 40.45
sound 2 33.16 - - - -
NICAM 33.05 33.05 32.35 33.05 39.80
*/
#define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/
#define PHILIPS_SET_PAL_BGDK 0x09
#define PHILIPS_SET_PAL_L2 0x0a
#define PHILIPS_SET_PAL_L 0x0b
/* system switching for Philips FI1216MF MK2
from datasheet "1996 Jul 09",
standard BG L L'
picture carrier 38.90 38.90 33.95
colour 34.47 34.37 38.38
sound 1 33.40 32.40 40.45
sound 2 33.16 - -
NICAM 33.05 33.05 39.80
*/
#define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */
#define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */
#define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */
/* Control byte */
#define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */
#define TUNER_RATIO_SELECT_50 0x00
#define TUNER_RATIO_SELECT_32 0x02
#define TUNER_RATIO_SELECT_166 0x04
#define TUNER_RATIO_SELECT_62 0x06
#define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */
/* Status byte */
#define TUNER_POR 0x80
#define TUNER_FL 0x40
#define TUNER_MODE 0x38
#define TUNER_AFC 0x07
#define TUNER_SIGNAL 0x07
#define TUNER_STEREO 0x10
#define TUNER_PLL_LOCKED 0x40
#define TUNER_STEREO_MK3 0x04
static DEFINE_MUTEX(tuner_simple_list_mutex);
static LIST_HEAD(hybrid_tuner_instance_list);
struct tuner_simple_priv {
unsigned int nr;
u16 last_div;
struct tuner_i2c_props i2c_props;
struct list_head hybrid_tuner_instance_list;
unsigned int type;
struct tunertype *tun;
u32 frequency;
u32 bandwidth;
};
/* ---------------------------------------------------------------------- */
static int tuner_read_status(struct dvb_frontend *fe)
{
struct tuner_simple_priv *priv = fe->tuner_priv;
unsigned char byte;
if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1))
return 0;
return byte;
}
static inline int tuner_signal(const int status)
{
return (status & TUNER_SIGNAL) << 13;
}
static inline int tuner_stereo(const int type, const int status)
{
switch (type) {
case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FM1256_IH3:
case TUNER_LG_NTSC_TAPE:
return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
default:
return status & TUNER_STEREO;
}
}
static inline int tuner_islocked(const int status)
{
return (status & TUNER_FL);
}
static inline int tuner_afcstatus(const int status)
{
return (status & TUNER_AFC) - 2;
}
static int simple_get_status(struct dvb_frontend *fe, u32 *status)
{
struct tuner_simple_priv *priv = fe->tuner_priv;
int tuner_status;
if (priv->i2c_props.adap ==