/*
* mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner
*
* Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include "tuner-i2c.h"
#include "mxl5007t.h"
static DEFINE_MUTEX(mxl5007t_list_mutex);
static LIST_HEAD(hybrid_tuner_instance_list);
static int mxl5007t_debug;
module_param_named(debug, mxl5007t_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debug level");
/* ------------------------------------------------------------------------- */
#define mxl_printk(kern, fmt, arg...) \
printk(kern "%s: " fmt "\n", __func__, ##arg)
#define mxl_err(fmt, arg...) \
mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg)
#define mxl_warn(fmt, arg...) \
mxl_printk(KERN_WARNING, fmt, ##arg)
#define mxl_info(fmt, arg...) \
mxl_printk(KERN_INFO, fmt, ##arg)
#define mxl_debug(fmt, arg...) \
({ \
if (mxl5007t_debug) \
mxl_printk(KERN_DEBUG, fmt, ##arg); \
})
#define mxl_fail(ret) \
({ \
int __ret; \
__ret = (ret < 0); \
if (__ret) \
mxl_printk(KERN_ERR, "error %d on line %d", \
ret, __LINE__); \
__ret; \
})
/* ------------------------------------------------------------------------- */
enum mxl5007t_mode {
MxL_MODE_ISDBT = 0,
MxL_MODE_DVBT = 1,
MxL_MODE_ATSC = 2,
MxL_MODE_CABLE = 0x10,
};
enum mxl5007t_chip_version {
MxL_UNKNOWN_ID = 0x00,
MxL_5007_V1_F1 = 0x11,
MxL_5007_V1_F2 = 0x12,
MxL_5007_V4 = 0x14,
MxL_5007_V2_100_F1 = 0x21,
MxL_5007_V2_100_F2 = 0x22,
MxL_5007_V2_200_F1 = 0x23,
MxL_5007_V2_200_F2 = 0x24,
};
struct reg_pair_t {
u8 reg;
u8 val;
};
/* ------------------------------------------------------------------------- */
static struct reg_pair_t init_tab[] = {
{ 0x02, 0x06 },
{ 0x03, 0x48 },
{ 0x05, 0x04 },
{ 0x06, 0x10 },
{ 0x2e, 0x15 }, /* OVERRIDE */
{ 0x30, 0x10 }, /* OVERRIDE */
{ 0x45, 0x58 }, /* OVERRIDE */
{ 0x48, 0x19 }, /* OVERRIDE */
{ 0x52, 0x03 }, /* OVERRIDE */
{ 0x53, 0x44 }, /* OVERRIDE */
{ 0x6a, 0x4b }, /* OVERRIDE */
{ 0x76, 0x00 }, /* OVERRIDE */
{ 0x78, 0x18 }, /* OVERRIDE */
{ 0x7a, 0x17 }, /* OVERRIDE */
{ 0x85, 0x06 }, /* OVERRIDE */
{ 0x01, 0x01 }, /* TOP_MASTER_ENABLE */
{ 0, 0 }
};
static struct reg_pair_t init_tab_cable[] = {
{ 0x02, 0x06 },
{ 0x03, 0x48 },
{ 0x05, 0x04 },
{ 0x06, 0x10 },
{ 0x09, 0x3f },
{ 0x0a, 0x3f },
{ 0x0b, 0x3f },
{ 0x2e, 0x15 }, /* OVERRIDE */
{ 0x30, 0x10 }, /* OVERRIDE */
{ 0x45, 0x58 }, /* OVERRIDE */
{ 0x48, 0x19 }, /* OVERRIDE */
{ 0x52, 0x03 }, /* OVERRIDE */
{ 0x53, 0x44 }, /* OVERRIDE */
{ 0x6a, 0x4b }, /* OVERRIDE */
{ 0x76, 0x00 }, /* OVERRIDE */
{ 0x78, 0x18 }, /* OVERRIDE */
{ 0x7a, 0x17 }, /* OVERRIDE */
{ 0x85, 0x06 }, /* OVERRIDE */
{ 0x01, 0x01 }, /* TOP_MASTER_ENABLE */
{ 0, 0 }
};
/* ------------------------------------------------------------------------- */
static struct reg_pair_t reg_pair_rftune[] = {
{ 0x0f, 0x00 }, /* abort tune */
{ 0x0c, 0x15 },
{ 0x0d, 0x40 },
{ 0x0e, 0x0e },
{ 0x1f, 0x87 }, /* OVERRIDE */
{ 0x20, 0x1f }, /* OVERRIDE */
{ 0x21, 0x87 }, /* OVERRIDE */
{ 0x22, 0x1f }, /* OVERRIDE */
{ 0x80, 0x01 }, /* freq dependent */
{ 0x0f, 0x01 }, /* start tune */
{ 0, 0 }
};
/* ------------------------------------------------------------------------- */
struct mxl5007t_state {
struct list_head hybrid_tuner_instance_list;
struct tuner_i2c_props i2c_props;
struct mutex lock;
struct mxl5007t_config *config;
enum mxl5007t_chip_version chip_id;
struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)];
struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)];
struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)];
enum mxl5007t_if_freq if_freq;
u32 frequency;
u32 bandwidth;
};
/* ------------------------------------------------------------------------- */
/* called by _init and _rftun to manipulate the register arrays */
static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val)
{
unsigned int i = 0;
while (reg_pair[i