/*
* Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com)
*
* 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, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include <linux/vmalloc.h>
#include <linux/i2c.h>
#include "mxl111sf.h"
#include "mxl111sf-reg.h"
#include "mxl111sf-phy.h"
#include "mxl111sf-i2c.h"
#include "mxl111sf-gpio.h"
#include "mxl111sf-demod.h"
#include "mxl111sf-tuner.h"
#include "lgdt3305.h"
int dvb_usb_mxl111sf_debug;
module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level "
"(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able)).");
int dvb_usb_mxl111sf_isoc;
module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644);
MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc).");
#define ANT_PATH_AUTO 0
#define ANT_PATH_EXTERNAL 1
#define ANT_PATH_INTERNAL 2
int dvb_usb_mxl111sf_rfswitch =
#if 0
ANT_PATH_AUTO;
#else
ANT_PATH_EXTERNAL;
#endif
module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644);
MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int).");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define deb_info(args...) dprintk(dvb_usb_mxl111sf_debug, 0x13, args)
#define deb_reg(args...) dprintk(dvb_usb_mxl111sf_debug, 0x08, args)
#define deb_adv(args...) dprintk(dvb_usb_mxl111sf_debug, MXL_ADV_DBG, args)
int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
{
int wo = (rbuf == NULL || rlen == 0); /* write-only */
int ret;
u8 sndbuf[1+wlen];
deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
memset(sndbuf, 0, 1+wlen);
sndbuf[0] = cmd;
memcpy(&sndbuf[1], wbuf, wlen);
ret = (wo) ? dvb_usb_generic_write(d, sndbuf, 1+wlen) :
dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
mxl_fail(ret);
return ret;
}
/* ------------------------------------------------------------------------ */
#define MXL_CMD_REG_READ 0xaa
#define MXL_CMD_REG_WRITE 0x55
int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data)
{
u8 buf[2];
int ret;
ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2);
if (mxl_fail(ret)) {
mxl_debug("error reading reg: 0x%02x", addr);
goto fail;
}
if (buf[0] == addr)
*data = buf[1];
else {
err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x",
addr, buf[0], buf[1]);
ret = -EINVAL;
}
deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data);
fail:
return ret;
}
int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data)
{
u8 buf[] = { addr, data };
int ret;
deb_reg("W: (0x%02x, 0x%02x)\n", addr, data);
ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0);
if (mxl_fail(ret))
err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
return ret;
}
/* ------------------------------------------------------------------------ */
int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
u8 addr, u8 mask, u8 data)
{
int ret;
u8 val;
if (mask != 0xff) {
ret = mxl111sf_read_reg(state, addr, &val);
#if 1
/* dont know why this usually errors out on the first try */
if (mxl_fail(ret))
err("error writing addr: 0x%02x, mask: 0x%02x, "
"data: 0x%02x, retrying...", addr, mask, data);
ret = mxl111sf_read_reg(state, addr, &val);
#endif
if (mxl_fail(ret))
goto fail;
}
val &= ~mask;
val