/*
* Afatech AF9013 demodulator driver
*
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
* Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
*
* Thanks to Afatech who kindly provided information.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "af9013_priv.h"
/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 64
struct af9013_state {
struct i2c_adapter *i2c;
struct dvb_frontend fe;
struct af9013_config config;
/* tuner/demod RF and IF AGC limits used for signal strength calc */
u8 signal_strength_en, rf_50, rf_80, if_50, if_80;
u16 signal_strength;
u32 ber;
u32 ucblocks;
u16 snr;
u32 bandwidth_hz;
enum fe_status fe_status;
unsigned long set_frontend_jiffies;
unsigned long read_status_jiffies;
bool first_tune;
bool i2c_gate_state;
unsigned int statistics_step:3;
struct delayed_work statistics_work;
};
/* write multiple registers */
static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg,
const u8 *val, int len)
{
int ret;
u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg[1] = {
{
.addr = priv->config.i2c_addr,
.flags = 0,
.len = 3 + len,
.buf = buf,
}
};
if (3 + len > sizeof(buf)) {
dev_warn(&priv->i2c->dev,
"%s: i2c wr reg=%04x: len=%d is too big!\n",
KBUILD_MODNAME, reg, len);
return -EINVAL;
}
buf[0] = (reg >> 8) & 0xff;
buf[1] = (reg >> 0) & 0xff;
buf[2] = mbox;
memcpy(&buf[3], val, len);
ret = i2c_transfer(priv->i2c, msg, 1);
if (ret == 1) {
ret = 0;
} else {
dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%04x " \
"len=%d\n", KBUILD_MODNAME, ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
}
/* read multiple registers */
static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg,
u8 *val, int len)
{
int ret;
u8 buf[3];
struct i2c_msg msg[2] = {
{
.addr = priv->config.i2c_addr,
.flags = 0,
.len = 3,
.buf = buf,
}, {
.addr = priv->config.i2c_addr,
.flags = I2C_M_RD,
.len = len,
.buf = val,
}
};
buf[0] = (reg >> 8) & 0xff;
buf[1] = (reg >> 0) & 0xff;
buf[2] = mbox;
ret = i2c_transfer(priv->i2c, msg, 2);
if (ret == 2) {
ret = 0;
} else {
dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%04x " \
"len=%d\n", KBUILD_MODNAME, ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
}
/* write multiple registers */
static int af9013_wr_regs(struct af9013_state *priv, u16 reg, const u8 *val,
int len)
{
int ret, i;
u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0);
if ((priv->config.ts_mode == AF9013_TS_USB) &&
((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) {
mbox |= ((len - 1) << 2);
ret = af9013_wr_regs_i2c(priv, mbox, reg, val, len);
} else {
for (i = 0; i < len; i++) {
ret = af9013_wr_regs_i2c(priv, mbox, reg+i, val+i, 1);
if (ret)
goto err;
}
}
err:
return 0;
}
/* read multiple registers */
static int af9013_rd_regs(struct af9013_state *priv, u16 reg, u8 *val, int len)
{
int ret, i;
u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(0 << 0);
if ((priv->config.ts_mode == AF9013_TS_USB) &&
((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) {
mbox |= ((len - 1) << 2);
ret = af9013_rd_regs_i2c(priv, mbox, reg, val, len);
} else {
for (i = 0; i < len; i++) {
ret = af9013_rd_regs_i2c(priv, mbox, reg+i, val+i, 1);
if (ret)
goto err;
}
}
err:
return 0;
}
/* write single register */
static int af9013_wr_reg(struct af9013_state *priv, u16 reg, u8 val)
{
return af9013_wr_regs(priv, reg, &val, 1);
}
/* read single register */
static int af9013_rd_reg(struct af9013_state *priv, u16 reg, u8 *val)
{
return af9013_rd_regs(priv, reg, val, 1);
}
static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val,
u8 len)
{
u8 mbox = (1 << 7)|(1 << 6)|((len - 1) << 2)|(1 << 1)|(1 << 0);
return af9013_wr_regs_i2c(state, mbox, reg, val, len);
}
static int af9013_wr_reg_bits(struct af9013_state *state, u16 reg, int pos,
int len, u8 val)
{
int ret;
u8 tmp, mask;
/* no need for read if whole reg is written */
if (len != 8) {
ret = af9013_rd_reg(state, reg, &tmp);
if (ret)
return ret;
mask = (0xff >> (8 - len)) << pos;
val <<= pos;
tmp &= ~mask;
val |= tmp;
}
return af9013_wr_reg(state, reg, val);
}
static int af9013_rd_reg_bits(struct af9013_state *state, u16 reg, int pos,
int len, u8 *val)
{
int ret;
u8 tmp;
ret = af9013_rd_reg(state, reg, &tmp);
if (ret)
return ret;
*val = (tmp >> pos);
*val &= (0xff >> (8 - len));
return 0;
}
static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval)
{
int ret;
u8 pos;
u16 addr;
dev_dbg(&state->i2c->dev, "%s: gpio=%d gpioval=%02x\n",
__func__, gpio, gpioval);
/*
* GPIO0 & GPIO1 0xd735
* GPIO2 & GPIO3 0xd736
*/
switch (gpio) {
case 0:
case 1:
addr = 0xd735;
break;
case 2:
case 3:
addr = 0xd736;
break;
default:
dev_err(&state->i2c->dev, "%s: invalid gpio=%d\n",
KBUILD_MODNAME, gpio);
ret = -EINVAL;
goto err;
}
switch (gpio) {
case 0:
case 2:
pos = 0;
break;
case 1:
case
|