/*
*
* i2c tv tuner chip device driver
* core core, i.e. kernel interfaces, registering and so on
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/videodev.h>
#include <linux/init.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
#include <media/audiochip.h>
#include "msp3400.h"
#define UNSET (-1U)
/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
I2C_CLIENT_END
};
I2C_CLIENT_INSMOD;
/* insmod options used at init time => read/only */
static unsigned int addr = 0;
static unsigned int no_autodetect = 0;
static unsigned int show_i2c = 0;
/* insmod options used at runtime => read/write */
unsigned int tuner_debug = 0;
static unsigned int tv_range[2] = { 44, 958 };
static unsigned int radio_range[2] = { 65, 108 };
static char pal[] = "--";
static char secam[] = "--";
static char ntsc[] = "-";
module_param(addr, int, 0444);
module_param(no_autodetect, int, 0444);
module_param(show_i2c, int, 0444);
module_param(tuner_debug, int, 0644);
module_param_string(pal, pal, sizeof(pal), 0644);
module_param_string(secam, secam, sizeof(secam), 0644);
module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
module_param_array(tv_range, int, NULL, 0644);
module_param_array(radio_range, int, NULL, 0644);
MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
MODULE_LICENSE("GPL");
static struct i2c_driver driver;
static struct i2c_client client_template;
/* ---------------------------------------------------------------------- */
/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
static void set_tv_freq(struct i2c_client *c, unsigned int freq)
{
struct tuner *t = i2c_get_clientdata(c);
if (t->type == UNSET) {
tuner_warn ("tuner type not set\n");
return;
}
if (NULL == t->tv_freq) {
tuner_warn ("Tuner has no way to set tv freq\n");
return;
}
if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
freq / 16, freq % 16 * 100 / 16, tv_range[0],
tv_range[1]);
}
t->tv_freq(c, freq);
}
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
{
struct tuner *t = i2c_get_clientdata(c);
if (t->type == UNSET) {
tuner_warn ("tuner type not set\n");
return;
}
if (NULL == t->radio_freq) {
tuner_warn ("tuner has no way to set radio frequency\n");
return;
}
if (freq <= radio_range[0] * 16000 || freq >= radio_range[1] * 16000) {
tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
freq / 16000, freq % 16000 * 100 / 16000,
radio_range[0], radio_range[1]);
}
t->radio_freq(c, freq);
return;
}
static void set_freq(struct i2c_client *c, unsigned long freq)
{
struct tuner *t = i2c_get_clientdata(c);
switch (t->mode) {
case V4L2_TUNER_RADIO:
tuner_dbg("radio freq set to %lu.%02lu\n",
freq / 16000, freq % 16000 * 100 / 16000);
set_radio_freq(c, freq);
break;
case V4L2_TUNER_ANALOG_TV:
case V4L2_TUNER_DIGITAL_TV:
tuner_dbg("tv freq set to %lu.%02lu\n",
freq / 16, freq % 16 * 100 / 16);
set_tv_freq(c, freq);
break;
}
t->freq = freq;
}
static void set_type(struct i2c_client *c, unsigned int type,
unsigned int new_mode_mask)
{
struct tuner *t = i2c_get_clientdata(c);
unsigned char buffer[4];
if (type == UNSET || type == TUNER_ABSENT) {
tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
return;
}
if (type >= tuner_count) {
tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
return;
}
/* This code detects calls by card attach_inform */
if (NULL == t->i2c.dev.driver) {