/* tuner-xc2028
*
* Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
*
* Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
* - frontend interface
*
* This code is placed under the terms of the GNU General Public License v2
*/
#include <linux/i2c.h>
#include <asm/div64.h>
#include <linux/firmware.h>
#include <linux/videodev2.h>
#include <linux/delay.h>
#include <media/tuner.h>
#include <linux/mutex.h>
#include "tuner-i2c.h"
#include "tuner-xc2028.h"
#include "tuner-xc2028-types.h"
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
static char audio_std[8];
module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
MODULE_PARM_DESC(audio_std,
"Audio standard. XC3028 audio decoder explicitly "
"needs to know what audio\n"
"standard is needed for some video standards with audio A2 or NICAM.\n"
"The valid values are:\n"
"A2\n"
"A2/A\n"
"A2/B\n"
"NICAM\n"
"NICAM/A\n"
"NICAM/B\n");
static char firmware_name[FIRMWARE_NAME_MAX];
module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
"default firmware name\n");
static LIST_HEAD(xc2028_list);
static DEFINE_MUTEX(xc2028_list_mutex);
/* struct for storing firmware table */
struct firmware_description {
unsigned int type;
v4l2_std_id id;
__u16 int_freq;
unsigned char *ptr;
unsigned int size;
};
struct firmware_properties {
unsigned int type;
v4l2_std_id id;
v4l2_std_id std_req;
__u16 int_freq;
unsigned int scode_table;
int scode_nr;
};
struct xc2028_data {
struct list_head xc2028_list;
struct tuner_i2c_props i2c_props;
int (*tuner_callback) (void *dev,
int command, int arg);
void *video_dev;
int count;
__u32 frequency;
struct firmware_description *firm;
int firm_size;
__u16 firm_version;
__u16 hwmodel;
__u16 hwvers;
struct xc2028_ctrl ctrl;
struct firmware_properties cur_fw;
struct mutex lock;
};
#define i2c_send(priv, buf, size) ({ \
int _rc; \
_rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \
if (size != _rc) \
tuner_info("i2c output error: rc = %d (should be %d)\n",\
_rc, (int)size); \
_rc; \
})
#define i2c_rcv(priv, buf, size) ({ \
int _rc; \
_rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \
if (size != _rc) \
tuner_err("i2c input error: rc = %d (should be %d)\n", \
_rc, (int)size); \
_rc; \
})
#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \
int _rc; \
_rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \
ibuf, isize); \
if (isize != _rc) \
tuner_err("i2c input error: rc = %d (should be %d)\n", \
_rc, (int)isize); \
_rc; \
})
#define send_seq(priv, data...) ({ \
static u8 _val[] = data; \
int _rc; \
if (sizeof(_val) != \
(_rc = tuner_i2c_xfer_send(&priv->i2c_props, \
_val, sizeof(_val)))) { \
tuner_err("Error on line %d: %d\n", __LINE__, _rc); \
} else \
msleep(10); \
_rc; \
})
static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
{
unsigned char buf[2];
unsigned char ibuf[2];
tuner_dbg("%s %04x called\n", __func__,