>> My plan goes this way.
>>
>> * dvb-usb provides the real I2C bus.
>> * the Host BIU is registered, which registers Virtual Bus #0 and #1
>> * the MASTER demod get's attached to VBus #0 - 0
>> * the MASTER tuner get's attached as a SLAVE on to the MASTER demod on
>> VBus #0 - 1
>> * the SLAVE demod get's attached to VBus #1
>> * the SLAVE tuner get's attached as a SLAVE on to the SLAVE demod on VBus #1
>> - 0
>> * firmware is downloaded via VBus #0 to the Host
After some efforts, i got to a stage where most things are done, except
for some small issues that i find a bit nasty.
Most of the nastiness can be seen in af901x_biu.c (i have added in the
comments near the relative areas)
The major issue that i face is that dvb-usb sees the Bus Interface as 2
objects (in the dual demod configuration), since there are 2 frontend's
being attached. (I don't see any clean way where i can do the BIU config
and or BIU specific access, which in fact happens only once)
Since i got a bit stuck up with frontend attach itself, temporarily left
out the firmware copy part.
Comments and thoughts would be interesting.
Thanks,
Manu
/*
AF-901x DVB-T demodulator driver
Copyright (c) Manu Abraham <[EMAIL PROTECTED]>
Copyright (c) AFA Technologies
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.
*/
#ifndef __AF901x_PRIV_H
#define __AF901x_PRIV_H
/**
* For the USB devices, the i2c_adapter is just virtual
* but on the PCIe devices, it is in fact a real bus
*/
struct af901x_state {
struct i2c_adapter *i2c_adapter;
struct af901x_config *config;
enum fe_status stat;
u32 ber;
u32 unc;
u16 abort_count;
struct dvb_frontend frontend;
enum fe_modulation constellation;
u32 fcw;
u8 unplug_th;
};
#endif //__AF901x_PRIV_H
/*
AF-901x DVB-T demodulator driver
Copyright (c) Manu Abraham <[EMAIL PROTECTED]>
Copyright (c) AFA Technologies
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.
*/
#ifndef __AF9015_H
#define __AF9015_H
#include <linux/dvb/frontend.h>
#define AF9015_DEFAULT_TS_PACKT_LEN 64
#define AF9015_DEFAULT_TS_FRAME_SIZE (64 * 188)
enum af901x_ts_mode {
AF901x_MPEG_PARALLEL = 0,
AF901x_MPEG_SERIAL,
AF901x_USB,
};
enum af901x_f_sample {
AF901x_FSAMPLE_28800 = 28800, /* 28.800 MHz */
AF901x_FSAMPLE_20480 = 20480, /* 20.480 MHz */
AF901x_FSAMPLE_28000 = 28000, /* 28.000 MHz */
AF901x_FSAMPLE_25000 = 25000, /* 25.000 MHz */
};
struct af901x_config {
u8 addr;
u8 slave;
u8 eeprom_addr;
u8 tuner_addr;
// interface setting
u32 frame_size;
u16 packt_size;
/* Initial settings*/
enum fe_bandwidth bandwidth;
u32 inversion; // convert to enum
enum af901x_ts_mode ts_mode;
enum af901x_f_sample f_sample; /* nyquist sampling */
u32 i_freq_0; /* IF 1 */
u32 i_freq_1; /* IF 2 */
// u32 osc_freq; /* OSC freq = nyquist freq */
};
#endif //__AF9015_H
/*
AF-9015 Bus Interface Unit driver
Copyright (c) Manu Abraham <[EMAIL PROTECTED]>
Copyright (c) AFA Technologies
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 "dvb-usb.h"
#include "af9015.h"
#include "af9015_fw.h"
#include "af9015_priv.h"
#include "af901x_reg.h"
#include "af901x_priv.h"
#include "af9015_rom.h"
static unsigned int verbose = 5;
module_param(verbose, int, 0644);
MODULE_PARM_DESC(verbose, "verbosity level");
u8 ucSN = 0;
/**
* NOTE! Currently we do bulk transfers for Control messages
* not very sure, whether this is the best approach we should
* take. Need to address this thought, once we have settled
* with the basic functionality.
*/
int af9015_biu_read(struct usb_device *udev, struct af9015_biu_msg *msg)
{
int i, err, length;
u8 buf[64];
/* EP 1 IN */
/**
* TODO! Probably it might make more sense to replace
* the hardcoded length of 255 with the length in the
* sent message, ie, msg->len
*/
err = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, 255,
&length, 1000);
if (err == 0) {
if (length == 0) {
printk("%s: Transaction error! length=%d\n",
__func__, length);
goto exit;
}
if (buf[0] != (ucSN - 1)) {
printk("%s: Sequence error! Seq RD=0x%02x,
Expect=0x%02x\n", __func__, buf[0], ucSN);
err = -EINVAL;
goto exit;
}
if (buf[1] != 0) {
printk("%s: Status check failed! Status=0x%02x\n",
__func__, buf[1]);
err = -EINVAL;
goto exit;
}
}
printk("%s: Data=[", __func__);
for (i = 0; i < (msg->length + 2); i++)
printk(" 0x%02x ", buf[i]);
printk("]\n");
memcpy(msg->data, &buf[2], msg->length);
// printk("%s: Data=[0x%02x]\n", __func__, msg->data[0]);
return 0;
exit:
printk("%s: Read Error\n", __func__);
return err;
}
/**
* NOTE! Currently we do bulk transfers for Control messages.
* not very sure, whether this is the best approach we should
* take. Need to address this thought, once we have settled
* with the basic functionality.
*/
int af9015_biu_write(struct usb_device *udev, struct af9015_biu_msg *msg)
{
int i, err, act_len;
u8 biu_msg[64] = {0};
u8 length = 0;
biu_msg[0] = msg->biu_cmd;
biu_msg[1] = ucSN;
biu_msg[2] = msg->addr;
biu_msg[3] = msg->reg_addr_msb; /* Register Address (MSB) */
biu_msg[4] = msg->reg_addr_lsb; /* Register Address (LSB) */
biu_msg[5] = 0; /* what to do with MAILBOX[5] commands ? */
biu_msg[6] = msg->addr_length; /* Reg addr bytes = 3, means SLAVE, So
what to do ? */
biu_msg[7] = msg->length;
/* TODO! Checksum */
// printk("%s: Header = [ ", __func__);
// for (i = 0; i < 8; i++)
// printk("0x%02x ", biu_msg[i]);
// printk("]\n");
switch (msg->biu_cmd) {
case AF9015_REQ_FWDOWNLOAD:
if (msg->length) /* There are cases with no data */
memcpy(&biu_msg[8], &msg->data[0], msg->length); /*
Copy data */
length = 8 + msg->length;
break;
default:
length = 8;
break;
}
printk("%s: Message = [ ", __func__);
for (i = 0; i < length; i++)
printk("0x%02x ", biu_msg[i]);
printk("]\n");
/* EP 2 OUT */
err = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), biu_msg, length,
&act_len, 1000);
ucSN += 1;
return err;
}
/**
* NOTE! This is the BIU protocol what we use. In fact this is not
* the default hardware protocol that's defined by the vendor, We
* try to make it look a bit nicer, by wrapping it around etc.
* Since there is no other documentation other than this, it
* is better to have it documented for reference purposes.
* Such a rework has been done,such that SLAVE demodulators
* are easily separable from Bus Interface Unit (BIU) integrated
* demodulators, which brings code reusability, without duplication.
*
* struct af9015_biu_msg {
* u16 addr; // Slave address
* enum af9015_biu_cmd biu_cmd; // BIU Command
* u16 flags;
* #define BIU_RD 0x01
* u8 *data; // Data
* u8 length; // Length of data
* };
*
* Where BIU Commands are defined thus:
*
* enum af9015_biu_cmd {
* AF9015_REQ_CURCONFIG = 0x10, // 1a) Get current config
* AF9015_REQ_FWDOWNLOAD = 0x11, // 2a) Download Firmware
control messages
* AF9015_REQ_CHKSUMCOMPUTE = 0x12, // 3a) Calculate Checksum
control messages
* AF9015_REQ_BOOTCONTROL = 0x13, // 4a) Boot control messages
* AF9015_REQ_BIUMMIO_RD = 0x20, // 5a) USB Memory RD control
messages
* AF9015_REQ_BIUMMIO_WR = 0x21, // 6a) USB Memory WR control
messages
* AF9015_REQ_GENERIC_I2C = 0x22, // 7a) General I2C control
messages
* AF9015_REQ_FWCOPY = 0x23, // 8a) Copy Firmware control
messages
* AF9015_REQ_SWRESET = 0x25, // 9) Software reset control
messages
* AF9015_REQ_CMDCTL = 0x26, // 10a) Control unit command
conrtol messages
* };
*
* Where Data is defined thus:
*
* Byte 0: Register Address (MSB)
* Byte 1: Register Address (LSB)
* Byte 2: Embedded MailBox Command
* Byte 3:+
* --- |
* --- |
* Byte n:+ Data for internal Memory Mapped Registers
*/
int af9015_biu_xfer(struct usb_device *udev, struct af9015_biu_msg *msgs, int
num)
{
int ret = 0, i;
for (i = 0; i < num; i++) {
// printk("%s: Msgs [%d of %d]\n", __func__, i, num);
if (msgs[i].flags & BIU_RD)
ret = af9015_biu_read(udev, &msgs[i]);
else
ret = af9015_biu_write(udev, &msgs[i]);
if (ret < 0) {
printk("%s: Transaction failure\n", __func__);
return ret;
}
}
return num;
}
static int af901x_fw_download(struct usb_device *udev, const struct firmware
*fw)
{
int i, err;
u8 config, *fw_array = packetArr;
u32 length, blocks, remainder;
struct af9015_biu_msg biu_config[] = {
{
.addr = 0x3a,
.biu_cmd = AF9015_REQ_CURCONFIG,
.reg_addr_msb = 0,
.reg_addr_lsb = 0,
.flags = 0,
.data = NULL,
.length = 0
},{
/* Current configuration */
.addr = 0x3a,
.biu_cmd = AF9015_REQ_CURCONFIG,
.flags = BIU_RD,
.data = &config,
.length = 1
}
};
struct af9015_biu_msg fw_download = {
/* Firmware download */
.addr = 0x3a,
.biu_cmd = AF9015_REQ_FWDOWNLOAD,
.flags = 0,
};
struct af9015_biu_msg boot = {
/* Boot demodulator */
.addr = 0x3a,
.biu_cmd = AF9015_REQ_BOOTCONTROL,
.flags = 0,
.data = NULL,
.length = 0
};
/* [STEP #1] Read current configuration */
printk("%s: Read current configuration\n", __func__);
if ((err = af9015_biu_xfer(udev, biu_config, 2)) != 2)
goto exit;
if (biu_config[1].data[0] != 1)
goto exit;
length = sizeof (packetArr) / sizeof (u8);
blocks = length / 63;
remainder = length % 63;
printk("%s: Array length=%d, Blocks=%d, Remainder=%d\n",
__func__, length, blocks, remainder);
/* [STEP #2] USB firmware download */
fw_download.reg_addr_msb = *(fw_array + 3);
fw_download.reg_addr_lsb = *(fw_array + 4);
fw_download.length = *(fw_array + 7);
fw_download.data = fw_array + 8;
for (i = 0; i < blocks; i++) {
printk("%s: Transferring FW Blocks [%d of %d]\n",
__func__, i, blocks);
if ((err = af9015_biu_xfer(udev, &fw_download, 1)) != 1)
goto exit;
fw_array += 63;
fw_download.reg_addr_msb = *(fw_array + 3);
fw_download.reg_addr_lsb = *(fw_array + 4);
fw_download.length = *(fw_array + 7);
fw_download.data = fw_array + 8;
}
if (remainder) {
fw_download.reg_addr_msb = *(fw_array + 3);
fw_download.reg_addr_lsb = *(fw_array + 4);
fw_download.length = *(fw_array + 7);
fw_download.data = fw_array + 8;
if ((err = af9015_biu_xfer(udev, &fw_download, 1)) != 1)
goto exit;
}
/* [STEP #3] Boot */
printk("%s: Booting the DSP core\n", __func__);
if ((err = af9015_biu_xfer(udev, &boot, 1)) != 1)
goto exit;
/* [STEP #4] Wait */
msleep(10);
/* [STEP #5] Read current configuration */
printk("%s: Read current configuration\n", __func__);
if ((err = af9015_biu_xfer(udev, biu_config, 2)) != 2)
goto exit;
if (biu_config[1].data[0] != 2) {
if (biu_config[1].data[0] == 1)
printk("%s: DSP Boot Code running still!, :-(\n",
__func__);
goto exit;
}
if (biu_config[1].data[0] == 2)
printk("%s: DSP Firmware running, we made it through! :)\n",
__func__);
return 0;
exit:
printk("%s: ERROR=%d\n", __func__, err);
return err;
}
#define MERC_EEPROM_I2C_ADDR 0x9A50
static int af9015_read_eeprom(struct usb_device *udev, u16 reg, u8 *data)
{
int err;
u8 r_data, addr_len;
u8 eeprom_reg[] = { ((reg >> 8) & 0xff), (reg & 0xff), 0x00 };
struct af9015_biu_msg mem_read[] = {
{
/* Memory read */
.addr = 0x2a,
.biu_cmd = AF9015_REQ_BIUMMIO_RD,
.reg_addr_msb = ((MERC_EEPROM_I2C_ADDR >> 8) & 0xff),
.reg_addr_lsb = (MERC_EEPROM_I2C_ADDR & 0xff),
.flags = 0,
.data = NULL,
.length = 1
},{
.flags = BIU_RD,
.data = &r_data,
.length = 1
}
};
struct af9015_biu_msg eeprom_read[] = {
{
/* EEPROM read */
.addr = 0xa1, /* EEPROM = 0x50 */
.biu_cmd = AF9015_REQ_GENERIC_I2C,
.reg_addr_msb = ((reg >> 8) & 0xff),
.reg_addr_lsb = (reg & 0xff),
.flags = 0,
.data = NULL,
.length = 1
},{
.flags = BIU_RD,
.data = data,
.length = 1
}
};
/* [STEP #1] Issue Memory Read Request */
// printk("%s: Memory Read Request @ 0x%02x Reg(MSB)=0x%02x
(LSB)=0x%02x\n",
// __func__,
// 0x2a,
// ((MERC_EEPROM_I2C_ADDR >> 8) & 0xff),
// (MERC_EEPROM_I2C_ADDR & 0xff));
if ((err = af9015_biu_xfer(udev, mem_read, 2)) != 2) {
printk("%s: Memory Read request failed\n", __func__);
goto exit;
}
if (r_data == 0) {
printk("%s: Data=0, Unexpected\n", __func__);
err = -EIO;
goto exit;
}
if (r_data < 0xa8) {
addr_len = 1;
} else {
addr_len = 2;
}
eeprom_read[0].addr_length = addr_len;
/* [STEP #2] Issue Eeprom Read Request */
// printk("%s: EEPROM Read Request @ 0x%02x Reg (MSB)=0x%02x
(LSB)=0x%02x\n",
// __func__, eeprom_read[0].addr, ((reg >> 8) & 0xff), (reg &
0xff));
if ((err = af9015_biu_xfer(udev, eeprom_read, 2)) != 2) {
printk("%s: EEPROM Read request failed\n", __func__);
goto exit;
}
*data = data[0];
// printk("%s: Data=[0x%02x]\n", __func__, *data);
return 0;
exit:
return err;
}
static int af9015_get_biu_config(struct af901x_biu *biu, struct af901x_config
*dmd_config)
{
int err;
u16 shift = 0;
u8 slave = 0;
u8 tmp[4];
struct af901x_biu_config *biu_config = &biu->biu_config;
biu->dmd_config = dmd_config;
#if 0
if (slave)
shift = EEPROM_SHIFT;
#endif
/* IR Table download */
if (!(err = af9015_read_eeprom(biu->udev->udev,
AF9015_CONFIG_ROM_IRMODE, tmp))) {
biu_config->ir_mode = tmp[0];
switch (biu_config->ir_mode) {
case AF9015_IRMODE_HID:
case AF9015_IRMODE_RLC:
case AF9015_IRMODE_RC6:
if (!(err = af9015_read_eeprom(biu->udev->udev,
AF9015_CONFIG_ROM_IRREMOTE, tmp))) {
biu_config->ir_type = tmp[0];
switch (biu_config->ir_type) {
case AF9015_IR_NEC:
printk("%s: IR/HID Mode=(NEC)\n",
__func__);
break;
case AF9015_IR_RC6:
printk("%s: IR/HID Mode=(RC6)\n",
__func__);
break;
default:
printk("%s: Unknown IR mode\n",
__func__);
err = -EINVAL;
}
}
break;
case AF9015_IRMODE_DISABLED:
default:
printk("%s: IR mode disabled\n", __func__);
break;
}
}
/* Dual TS option */
if (!(err = af9015_read_eeprom(biu->udev->udev,
AF9015_CONFIG_ROM_TSMODE, tmp))) {
biu_config->ts_mode = tmp[0];
printk("%s: Dual TS Mode = 0x%02X\n", __func__,
biu_config->ts_mode);
}
/* MPEG2 I2C addr */
if ((err = af9015_read_eeprom(biu->udev->udev,
AF9015_CONFIG_ROM_2WIREADDR, tmp))) {
biu_config->addr = AF901x_SLAVE_DEMOD_ADDR;
printk("%s: EEPROM_2WIREADDR Fail\n", __func__);
}
biu_config->addr = tmp[0];
printk("%s: 2 wire address = 0x%02x\n", __func__, biu_config->addr);
/* SAW filter bandwidth */
if (!(err = af9015_read_eeprom(biu->udev->udev,
AF9015_CONFIG_ROM_SAWBW1, tmp))) {
biu_config->saw_bw = tmp[0];
printk("%s: SAW filter bandwidth = %d Mhz\n", __func__,
biu_config->saw_bw);
}
if (!(err = af9015_read_eeprom(biu->udev->udev,
AF9015_CONFIG_ROM_XTALTYP1, tmp))) {
biu_config->osc_type = tmp[0];
switch (biu_config->osc_type) {
case 0:
dmd_config->f_sample = AF901x_FSAMPLE_28800;
break;
case 1:
dmd_config->f_sample = AF901x_FSAMPLE_20480;
break;
case 2:
dmd_config->f_sample = AF901x_FSAMPLE_28000;
break;
case 3:
dmd_config->f_sample = AF901x_FSAMPLE_25000;
break;
default:
err = -EINVAL;
};
printk("%s: Found Xtal Oscillator with freq = %d kHz,\n will
use the same frequency for the sampling rate as well.\n", __func__,
biu_config->osc_freq);
}
/* Tuner type */
if (!(err = af9015_read_eeprom(biu->udev->udev,
AF9015_CONFIG_ROM_TUNERID1, tmp))) {
biu_config->tuner = tmp[0];
printk("%s: Tuner type = 0x%02X\n", __func__,
biu_config->tuner);
switch (biu_config->tuner) {
case AF9015_TUNER_MT2060D:
printk("%s: Found a MT2060 digital tuner\n", __func__);
break;
case AF9015_TUNER_MXL5003D:
printk("%s: Found a MXL5003 digital tuner\n", __func__);
break;
case AF9015_TUNER_MXL5005H:
printk("%s: Found a MXL5005 Hybrid tuner\n", __func__);
break;
default:
printk("%s: Unknown tuner %d, please report\n",
__func__, biu_config->tuner);
err = -EINVAL;
}
}
/* IF0 */
if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_IF1H,
tmp)))
biu_config->i_freq_0 = tmp[0];
if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_IF1L,
tmp))) {
dmd_config->i_freq_0 <<= 8;
dmd_config->i_freq_0 |= tmp[0];
printk("%s: IF0 = %d\n",__func__, dmd_config->i_freq_0);
}
/* IF1 */
if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_IF2H,
tmp)))
biu_config->i_freq_1 = tmp[0];
if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_IF2L,
tmp))) {
biu_config->i_freq_1 <<= 8;
biu_config->i_freq_1 |= tmp[0];
printk("%s: IF1 = %d\n", __func__, biu_config->i_freq_1);
}
/* MT2060 IF0 */
if (!(err = af9015_read_eeprom(biu->udev->udev,
AF9015_CONFIG_ROM_MT2060_IF1H, tmp)))
biu_config->i_freq_0 = tmp[0];
if (!(err = af9015_read_eeprom(biu->udev->udev,
AF9015_CONFIG_ROM_MT2060_IF1L, tmp))) {
biu_config->i_freq_0 <<= 8;
biu_config->i_freq_0 |= tmp[0];
printk("%s: MT2060 IF0 = %d\n",__func__, biu_config->i_freq_0);
}
/* MT2060 IF1 */
if (!(err = af9015_read_eeprom(biu->udev->udev,
AF9015_CONFIG_ROM_MT2060_IF2H, tmp)))
biu_config->i_freq_1 = tmp[0];
if (!(err = af9015_read_eeprom(biu->udev->udev,
AF9015_CONFIG_ROM_MT2060_IF2L, tmp))) {
biu_config->i_freq_1 <<= 8;
biu_config->i_freq_1 |= tmp[0];
printk("%s: MT2060 IF1 = %d\n", __func__, biu_config->i_freq_1);
}
/* Spectral inversion */
if (!(err = af9015_read_eeprom(biu->udev->udev,
AF9015_CONFIG_ROM_IQINV1, tmp))) {
dmd_config->inversion = tmp[0];
printk("%s: Spectral Inversion = 0x%02X\n", __func__, tmp[0]);
}
return 0;
exit:
printk("%s: BIU EEPROM read failed err=%d\n", __func__, err);
return err;
}
static int af9015_read(struct i2c_adapter *v_bus, u16 reg, u8 *data)
{
return 0;
}
static int af9015_write(struct i2c_adapter *v_bus, u16 reg, u8 data)
{
return 0;
}
/* Mode 15 + 13 init config mode */
static int af9015_epconfig_mode_15(struct af901x_biu *biu)
{
struct i2c_adapter *v_bus = biu->adapter; /* Adapter 0 */
u8 reg, dual = 0;
/* TODO! Must move out end point configuration from in here */
// if (state->config->usb_11) { /** NOTE BIU config */
// /**
// * We need to put frame sizes and packet sizes
// * based on USB mode, ie 1.1/2.0
// */
// }
/* TS init */
af9015_read(v_bus, AF901x_MP2IF_2, ®);
AF901x_SETFIELD(MP2IF_2_SW_RESET, reg, 1); /* 0xd507 assert EP4 Reset */
af9015_write(v_bus, AF901x_MP2IF_2, reg);
af9015_read(v_bus, AF901x_MP2IF_3, ®);
AF901x_SETFIELD(MP2IF_3_SWRST, reg, 1); /* 0xd50b assert EP5 reset */
af9015_write(v_bus, AF901x_MP2IF_3, reg);
af9015_read(v_bus, AF901x_TX_ENABLE, ®);
AF901x_SETFIELD(TX_ENABLE_EP4, reg, 0); /* 0xdd11 disable EP4 */
af9015_write(v_bus, AF901x_TX_ENABLE, reg);
af9015_read(v_bus, AF901x_TX_ENABLE, ®);
AF901x_SETFIELD(TX_ENABLE_EP5, reg, 0); /* 0xdd11 disable EP5 */
af9015_write(v_bus, AF901x_TX_ENABLE, reg);
af9015_read(v_bus, AF901x_TX_ENABLE, ®);
AF901x_SETFIELD(TX_ENABLE_EP4, reg, 1); /* 0xdd11 enable EP4 */
af9015_write(v_bus, AF901x_TX_ENABLE, reg);
if (dual) {
af9015_read(v_bus, AF901x_TX_ENABLE, ®);
AF901x_SETFIELD(TX_ENABLE_EP5, reg, 1); /* 0xdd11 enable EP5 */
af9015_write(v_bus, AF901x_TX_ENABLE, reg);
}else {
af9015_read(v_bus, AF901x_TX_ENABLE, ®);
AF901x_SETFIELD(TX_ENABLE_EP5, reg, 0); /* 0xdd11 disable EP5 */
af9015_write(v_bus, AF901x_TX_ENABLE, reg);
}
af9015_read(v_bus, AF901x_TX_NAK, ®);
AF901x_SETFIELD(TX_NAK_EP4, reg, 0); /* disable EP4 NAK */
if (dual)
AF901x_SETFIELD(TX_NAK_EP5, reg, 0); /* disable EP5 NAK */
af9015_write(v_bus, AF901x_TX_NAK, reg);
af9015_read(v_bus, AF901x_MP2IF_0, ®); /* 0xd500 */
AF901x_SETFIELD(MP2IF_0_MPEG_PARALLEL, reg, 0); /* disable Parallel
mode */
AF901x_SETFIELD(MP2IF_0_MPEG_SERIAL, reg, 0); /* disable Serial mode */
af9015_write(v_bus, AF901x_MP2IF_0, reg);
if (dual) {
af9015_read(v_bus, AF901x_MP2IF_0, ®);
AF901x_SETFIELD(MP2IF_0_MPEG_SERIAL, reg, 1);
af9015_write(v_bus, AF901x_MP2IF_0, reg);
}
af9015_read(v_bus, AF901x_TX_LEN_EP4_LSB, ®); /* EP4 transfer length
*/
AF901x_SETFIELD(TX_LEN_EP4_LSB, reg, (BYTE0(TX_LEN_EP4_LSB,
AF9015_DEFAULT_TS_FRAME_SIZE)));
af9015_write(v_bus, AF901x_TX_LEN_EP4_LSB, reg);
af9015_read(v_bus, AF901x_TX_LEN_EP4_MSB, ®);
AF901x_SETFIELD(TX_LEN_EP4_MSB, reg, (BYTE1(TX_LEN_EP4_MSB,
AF9015_DEFAULT_TS_FRAME_SIZE)));
af9015_write(v_bus, AF901x_TX_LEN_EP4_MSB, reg);
if (dual) {
af9015_read(v_bus, AF901x_TX_LEN_EP5_LSB, ®); /* EP5
transfer length */
AF901x_SETFIELD(TX_LEN_EP5_LSB, reg, (BYTE0(TX_LEN_EP5_LSB,
AF9015_DEFAULT_TS_FRAME_SIZE)));
af9015_write(v_bus, AF901x_TX_LEN_EP5_LSB, reg);
af9015_read(v_bus, AF901x_TX_LEN_EP5_MSB, ®);
AF901x_SETFIELD(TX_LEN_EP4_MSB, reg, (BYTE1(TX_LEN_EP5_MSB,
AF9015_DEFAULT_TS_FRAME_SIZE)));
af9015_write(v_bus, AF901x_TX_LEN_EP5_MSB, reg);
}
af9015_read(v_bus, AF901x_MAX_PACKET_EP4, ®);
AF901x_SETFIELD(MAX_PACKET_EP4, reg, AF9015_DEFAULT_TS_PACKT_LEN);
af9015_write(v_bus, AF901x_MAX_PACKET_EP4, reg);
if (dual) {
af9015_read(v_bus, AF901x_MAX_PACKET_EP5, ®);
AF901x_SETFIELD(MAX_PACKET_EP5, reg,
AF9015_DEFAULT_TS_PACKT_LEN);
af9015_write(v_bus, AF901x_MAX_PACKET_EP5, reg);
}
if (dual) {
/* enable MP2IF */
af9015_read(v_bus, AF901x_MP2IF_3, ®);
AF901x_SETFIELD(MP2IF_3_EN, reg, 1); /* enable MP2IF */
af9015_write(v_bus, AF901x_MP2IF_3, reg);
} else {
af9015_read(v_bus, AF901x_MP2IF_3, ®);
AF901x_SETFIELD(MP2IF_3_EN, reg, 0); /* disable MP2IF */
af9015_write(v_bus, AF901x_MP2IF_3, reg);
}
af9015_read(v_bus, AF901x_MP2IF_2, ®);
AF901x_SETFIELD(MP2IF_2_SW_RESET, reg, 0); /* negate EP4 reset */
af9015_write(v_bus, AF901x_MP2IF_2, reg);
af9015_read(v_bus, AF901x_MP2IF_3, ®);
AF901x_SETFIELD(MP2IF_3_SWRST, reg, 0); /* negate EP5 reset */
af9015_write(v_bus, AF901x_MP2IF_3, reg);
if (dual) {
/* Set Serial output pin of 13 (data7) */
af9015_read(v_bus, AF901x_MP2IF_USB20, ®);
/* change output bit to Data 7, for the AF9013 */
if (!(AF901x_GETFIELD(MP2IF_USB20_MODE, reg))) {
af9015_read(v_bus, AF901x_MP2IF_0, ®);
AF901x_SETFIELD(MP2IF_0_MPEG_SERIAL7, reg, 1);
af9015_write(v_bus, AF901x_MP2IF_0, reg);
}
/* Split 9015 PSB to 1.5k + 0.5k, enable Flow Control */
af9015_read(v_bus, AF901x_MP2IF_3, ®);
AF901x_SETFIELD(MP2IF_3_HALF_PSB, reg, 1);
af9015_write(v_bus, AF901x_MP2IF_3, reg);
af9015_read(v_bus, AF901x_TSPARAM, ®);
AF901x_SETFIELD(TSPARAM_STOP_EN, reg, 1);
af9015_write(v_bus, AF901x_TSPARAM, reg);
af9015_read(v_bus, AF901x_MPEG_FULL_SPEED, ®);
AF901x_SETFIELD(MPEG_FULL_SPEED, reg, 1);
af9015_write(v_bus, AF901x_MPEG_FULL_SPEED, reg);
}
return 0;
}
/**
* NOTE! Mode 17 config
*
* We don't use this mode on any PC based devices
* For a specific consumer handheld device with a
* MPEG2 decoder
*/
static int af9015_epconfig_mode_17(struct af901x_biu *biu)
{
struct i2c_adapter *v_bus = biu->adapter; /* Adapter 0 */
u8 reg;
// if (state->config->usb_11) { /** NOTE BIU config */
// /**
// * We need to put frame sizes and packet sizes
// * based on USB mode, ie 1.1/2.0
// */
// }
af9015_read(v_bus, AF901x_MP2IF_3, ®);
AF901x_SETFIELD(MP2IF_3_SWRST, reg, 1); /* 0xd50b assert EP5 reset */
af9015_write(v_bus, AF901x_MP2IF_3, reg);
af9015_read(v_bus, AF901x_TX_ENABLE, ®);
AF901x_SETFIELD(TX_ENABLE_EP5, reg, 0); /* 0xdd11 disable EP5 */
af9015_write(v_bus, AF901x_TX_ENABLE, reg);
af9015_read(v_bus, AF901x_TX_ENABLE, ®);
AF901x_SETFIELD(TX_ENABLE_EP5, reg, 1); /* 0xdd11 enable EP5 */
af9015_write(v_bus, AF901x_TX_ENABLE, reg);
af9015_read(v_bus, AF901x_TX_NAK, ®);
AF901x_SETFIELD(TX_NAK_EP5, reg, 0); /* disable EP5 NAK */
af9015_write(v_bus, AF901x_TX_NAK, reg);
af9015_read(v_bus, AF901x_TX_LEN_EP5_LSB, ®); /* EP5 transfer length
*/
AF901x_SETFIELD(TX_LEN_EP5_LSB, reg, (BYTE0(TX_LEN_EP5_LSB,
AF9015_DEFAULT_TS_FRAME_SIZE)));
af9015_write(v_bus, AF901x_TX_LEN_EP5_LSB, reg);
af9015_read(v_bus, AF901x_TX_LEN_EP5_MSB, ®);
AF901x_SETFIELD(TX_LEN_EP4_MSB, reg, (BYTE1(TX_LEN_EP5_MSB,
AF9015_DEFAULT_TS_FRAME_SIZE)));
af9015_write(v_bus, AF901x_TX_LEN_EP5_MSB, reg);
af9015_read(v_bus, AF901x_MAX_PACKET_EP5, ®);
AF901x_SETFIELD(MAX_PACKET_EP5, reg, AF9015_DEFAULT_TS_PACKT_LEN);
af9015_write(v_bus, AF901x_MAX_PACKET_EP5, reg);
af9015_read(v_bus, AF901x_MP2IF_0, ®); /* 0xd500 */
AF901x_SETFIELD(MP2IF_0_MPEG_SERIAL, reg, 1); /* enable Serial mode */
af9015_write(v_bus, AF901x_MP2IF_0, reg);
af9015_read(v_bus, AF901x_MP2IF_0, ®); /* 0xd500 */
AF901x_SETFIELD(MP2IF_0_MPEG_PARALLEL, reg, 0); /* disable Parallel
mode */
af9015_write(v_bus, AF901x_MP2IF_0, reg);
/* enable MP2IF */
af9015_read(v_bus, AF901x_MP2IF_3, ®);
AF901x_SETFIELD(MP2IF_3_EN, reg, 1); /* enable MP2IF */
af9015_write(v_bus, AF901x_MP2IF_3, reg);
af9015_read(v_bus, AF901x_MP2IF_3, ®);
AF901x_SETFIELD(MP2IF_3_SWRST, reg, 0); /* negate EP5 reset */
af9015_write(v_bus, AF901x_MP2IF_3, reg);
return 0;
}
extern struct dvb_frontend *af901x_attach(struct i2c_adapter *i2c_adapter,
struct af901x_config *config);
static int af9015_frontend_attach(struct dvb_usb_adapter *adap)
{
int err = 0;
struct af901x_biu *biu = adap->dev->priv;
struct i2c_adapter *i2c = biu->adapter;
struct af901x_config demod_config;
biu->udev = adap->dev;
/**
* TODO! Loading defaults, depends on the config
* no hardcoded values please
*/
demod_config.bandwidth = BANDWIDTH_6_MHZ;
/**
* TODO! *Bloody Hell !* It sucks to do like this
* Need to do it in a better way, this is _crap_
*/
//------------------------
printk("%s: Initializing I2C\n", __func__);
af9015_i2c_init(biu);
printk("%s: Retrieving BIU config\n", __func__);
af9015_get_biu_config(biu, &demod_config);
//------------------------
printk("%s: Attaching Master demodulator\n", __func__);
if (!(adap->fe = af901x_attach(i2c, &demod_config))) {
printk("%s: AF9015 MASTER demodulator attach failed. :-(\n\n
\
This is a very unlikely case, so surely there is a
bug\n \
some place. All the singing happens on the\n
\
Linux DVB Mailing List <[email protected]>\n
\
Please join the chorus at Linux DVB. ;-)\n",
__func__);
err = -EIO;
goto exit;
}
printk("%s: AF9015 Master demodulator successfully attached\n",
__func__);
/**
* TODO! How do we attach multiple frontends in our circumstance ?
* A bit lost in thoughts, atm. Ever thought about circles ?
*/
return 0;
exit:
printk("%s: Quite nasty indeed!\n", __func__);
return err;
}
static int af901x_frontend_attach(struct dvb_usb_adapter *adap)
{
int err = 0;
struct af901x_biu *biu = adap->dev->priv;
struct i2c_adapter *i2c = biu->adapter;
struct af901x_config demod_config;
i2c++; /* Virtual world 1 */
/**
* We already initialized I2C and as well
* read the BIU config. What to do now ?
*/
printk("%s: Attaching Slave demodulator\n", __func__);
if (!(adap->fe = af901x_attach(i2c, &demod_config))) {
printk("%s: AF9015 SLAVE demodulator attach failed.\n",
__func__);
err = -EIO;
goto exit;
}
printk("%s: AF901x SLAVE demodulator successfully attached\n",
__func__);
return 0;
exit:
printk("%s: Quite nasty indeed!\n", __func__);
return err;
}
static struct dvb_usb_device_properties af9015_properties;
static struct af9015_biuconfig_mode af9015_ref_pcusb_dev = {
.biu_mode = AF9015_BIU_MODE_15,
.usb_mode = AF9015_USB_MODE_20
/* TODO! add in demod and tuner I2C addresses */
};
// static struct af9015_biuconfig_mode af9015_azurewave_vp704j = {
// .biu_mode = AF9015_BIU_MODE_15,
// .usb_mode = AF9015_USB_MODE_20
// /* TODO! add in demod and tuner I2C addresses */
// };
static int af9015_biu_epconfig(struct af901x_biu *biu)
{
int err = 0;
struct af9015_biuconfig_mode *biuconfig_mode = &biu->config_mode;
/* TODO! Need to do this conditionally for each device based on ID's */
memcpy(&biuconfig_mode, &af9015_ref_pcusb_dev, sizeof (struct
af9015_biuconfig_mode));
switch (biuconfig_mode->biu_mode) {
case AF9015_BIU_MODE_15:
printk("%s: Using MODE 15\n", __func__);
af9015_epconfig_mode_15(biu);
break;
case AF9015_BIU_MODE_17:
printk("%s: Using MODE 17\n", __func__);
af9015_epconfig_mode_17(biu);
break;
default:
err = -EINVAL;
break;
}
return err;
}
static int af9015_usb_probe(struct usb_interface *intf, const struct
usb_device_id *id)
{
int err;
struct dvb_usb_device *dev;
struct af901x_biu *biu;
printk("%s: probing for a AF9015\n", __func__);
if ((err = dvb_usb_device_init(intf, &af9015_properties, THIS_MODULE,
&dev)))
printk("%s error %d\n", __FUNCTION__, err);
dev = usb_get_intfdata(intf);
// biu = dev->priv;
// biu->udev = dev;
//
// printk("%s: Initializing I2C\n", __func__);
// af9015_i2c_init(biu);
// printk("%s: Retrieving BIU config\n", __func__);
// af9015_get_biu_config(biu);
// printk("%s: Initializing BIU\n", __func__);
// af9015_biu_epconfig(biu);
return err;
}
static void af9015_usb_device_exit(struct usb_interface *intf)
{
struct af901x_biu *biu;
struct dvb_usb_device *dev = usb_get_intfdata(intf);
biu = dev->priv;
biu->udev = dev;
af9015_i2c_exit(biu);
dvb_usb_device_exit(intf);
}
static struct usb_device_id af9015_usb_table[] = {
{ USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015) },
{ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_VP704J) },
{ 0 },
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
static struct dvb_usb_device_properties af9015_properties = {
.firmware = "dvb-usb-af9015.fw",
.download_firmware = af901x_fw_download,
.size_of_priv = sizeof (struct af901x_biu),
.no_reconnect = 1,
.num_adapters = 1,
.adapter = {
{
.frontend_attach = af9015_frontend_attach,
.stream = {
.type = USB_BULK,
.count = 4,
.endpoint = 0x84,
.u = {
.bulk = {
.buffersize = 4096, /* actual
size seen is 3948 */
}
}
},
}
},
.num_device_descs = 1,
.devices = {
{
.name = "Afatech 9015 DVB-T",
.cold_ids = { af9015_usb_table, NULL },
.warm_ids = { NULL },
},{ NULL },
}
};
static struct usb_driver af9015_driver = {
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.owner = THIS_MODULE,
#endif
.name = "dvb-usb-af9015",
.probe = af9015_usb_probe,
.disconnect = af9015_usb_device_exit,
.id_table = af9015_usb_table,
};
static int __init af9015_init(void)
{
int result;
printk("%s: Initializing AF9015\n", __func__);
if ((result = usb_register(&af9015_driver))) {
err("usb_register failed. (%d)", result);
return result;
}
return 0;
}
static void __exit af9015_exit(void)
{
printk("%s: AF9015 exiting\n", __func__);
usb_deregister(&af9015_driver);
}
module_init(af9015_init);
module_exit(af9015_exit);
MODULE_AUTHOR("Manu Abraham <[EMAIL PROTECTED]>");
MODULE_DESCRIPTION("AF9015 DVB-T");
MODULE_LICENSE("GPL");
/*
AF-9015 Bus Interface Unit driver
Copyright (c) Manu Abraham <[EMAIL PROTECTED]>
Copyright (c) AFA Technologies
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 <linux/kernel.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include "af9015_priv.h"
#include "dvb-usb.h"
#include <linux/mutex.h>
/**
* NOTE! This is the BIU protocol what we use. In fact this is not
* the default hardware protocol that's defined by the vendor, We
* try to make it look a bit nicer, by wrapping it around etc.
* Since there is no other documentation other than this, it
* is better to have it documented for reference purposes.
* Such a rework has been done,such that SLAVE demodulators
* are easily separable from Bus Interface Unit (BIU) integrated
* demodulators, which brings code reusability, without duplication.
*
* struct af9015_biu_msg {
* u16 addr; // Slave address
* enum af9015_biu_cmd biu_cmd; // BIU Command
* u16 flags;
* #define BIU_RD 0x01
* u8 *data; // Data
* u8 length; // Length of data
* };
*
* Where BIU Commands are defined thus:
*
* enum af9015_biu_cmd {
* AF9015_REQ_CURCONFIG = 0x10, // 1a) Get current config
* AF9015_REQ_FWDOWNLOAD = 0x11, // 2a) Download Firmware
control messages
* AF9015_REQ_CHKSUMCOMPUTE = 0x12, // 3a) Calculate Checksum
control messages
* AF9015_REQ_BOOTCONTROL = 0x13, // 4a) Boot control messages
* AF9015_REQ_BIUMMIO_RD = 0x20, // 5a) USB Memory RD control
messages
* AF9015_REQ_BIUMMIO_WR = 0x21, // 6a) USB Memory WR control
messages
* AF9015_REQ_GENERIC_I2C = 0x22, // 7a) General I2C control
messages
* AF9015_REQ_FWCOPY = 0x23, // 8a) Copy Firmware control
messages
* AF9015_REQ_SWRESET = 0x25, // 9) Software reset control
messages
* AF9015_REQ_CMDCTL = 0x26, // 10a) Control unit command
conrtol messages
* };
*
* Where Data is defined thus:
*
* //Byte 0: Bus Interface Unit (BIU) Command
* //Byte 1: Register Address (MSB)
* //Byte 2: Register Address (LSB)
* //Byte 3: Embedded MailBox Command
* Byte 0: Register Address (MSB)
* Byte 1: Register Address (LSB)
* Byte 2: Embedded MailBox Command
* Byte 3:+
* --- |
* --- |
* Byte n:+ Data for internal Memory Mapped Registers
*/
/**
* NOTE! We will ignore the EEPROM for now. Technically it is not
* on an I2C bus, but a 2 wire bus, memory mapped. Thus virtual.
* Transactions with the EEPROM at the earliest stage where there
* wouldn't be any other transactions. In fact the firmware
* download would happen much later after the EEPROM transactions.
* This is in contradiction to what we do currently.
*/
static int af9015_read_regs(struct af901x_biu *biu, struct i2c_msg *msgs)
{
int err = 0;
struct af9015_biu_msg msg = {
.flags = BIU_RD,
.data = msgs[1].buf,
.length = msgs[1].len
};
if ((err = af9015_biu_read(biu->udev->udev, &msg) < 0)) {
printk("%s: Read error\n", __func__);
err = -EIO;
goto exit;
}
return 0;
exit:
return err;
}
static int af9015_write_regs(struct af901x_biu *biu, struct i2c_msg *msgs, int
flags)
{
int err = 0;
u16 reg_addr = 0;
struct af9015_biu_msg msg = {
.addr = 0x3a,
.reg_addr_msb = msgs->buf[0],
.reg_addr_lsb = msgs->buf[1],
.flags = 0,
.data = &msgs->buf[2],
.length = msgs->len
};
reg_addr |= msgs->buf[0];
reg_addr <<= 8;
reg_addr |= msgs->buf[1];
if ((reg_addr == 0xff00) || (reg_addr == 0xae00)) {
msg.biu_cmd = AF9015_REQ_CMDCTL; /* looks incorrect */
} else {
/**
* Any better methods possibles for identification ?
* Or can this be made better somehow
*/
if (flags)
msg.biu_cmd = AF9015_REQ_BIUMMIO_RD;
else
msg.biu_cmd = AF9015_REQ_BIUMMIO_WR;
}
if ((err = af9015_biu_write(biu->udev->udev, &msg) < 0)) {
printk("%s: Write Error\n", __func__);
err = -EIO;
goto exit;
}
return 0;
exit:
return err;
}
static int af9015_virt_0_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs,
int num)
{
struct af901x_biu *biu;
int i, ret = 0;
biu = i2c_get_adapdata(i2c);
if (mutex_lock_interruptible(&biu->biu_lock)) {
printk("%s: Physical Bus in use, will try later\n", __func__);
return -ERESTARTSYS;
}
for (i = 0; i < num; i++) {
printk("%s: Msgs [%d of %d]\n", __func__, i, num);
if (msgs[i].flags & BIU_RD)
ret = af9015_read_regs(biu, msgs);
else
/**
* NOTE! Doubting Thomas
*
* Internally write needs to know whether we are writing
* for a pure write or a partial write for a read
* in case of read, we identify the operation as a write
* operation for a read.
* Write (Flags = 0), Read (Flags = 1)
* Also we do not have the READ flag in the first
message
* First message always contains the partial write and
* hence therefore i + 1
*/
ret = af9015_write_regs(biu, msgs, msgs[i + 1].flags);
if (ret < 0) {
printk("%s: Transaction failure\n", __func__);
return ret;
}
}
mutex_unlock(&biu->biu_lock);
return num;
}
static int af9015_virt_1_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg
*msgs, int num)
{
return 0;
}
static int af9015_virt_2_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg
*msgs, int num)
{
return 0;
}
static u32 af9015_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C;
}
static struct i2c_algorithm af9015_algo[] = {
{
.master_xfer = af9015_virt_0_xfer,
.functionality = af9015_i2c_func,
},{
.master_xfer = af9015_virt_1_xfer,
.functionality = af9015_i2c_func,
},{
.master_xfer = af9015_virt_2_xfer,
.functionality = af9015_i2c_func,
}
};
#define I2C_HW_B_AF9015 0x30
static struct i2c_adapter af9015_i2c_adapter[] = {
{
.owner = THIS_MODULE,
.name = "AF9015 Virual Adapter-0",
.id = I2C_HW_B_AF9015,
.class = I2C_CLASS_TV_DIGITAL,
.algo = &af9015_algo[0],
},{
.owner = THIS_MODULE,
.name = "AF9015 Virual Adapter-1",
.id = I2C_HW_B_AF9015,
.class = I2C_CLASS_TV_DIGITAL,
.algo = &af9015_algo[1],
},{
.owner = THIS_MODULE,
.name = "AF9015 Virual Adapter-2",
.id = I2C_HW_B_AF9015,
.class = I2C_CLASS_TV_DIGITAL,
.algo = &af9015_algo[2],
}
};
#define AF9015_MAX_VIRTUAL_ADAPTERS 3
int __devinit af9015_i2c_init(struct af901x_biu *biu)
{
struct i2c_adapter *i2c = biu->adapter;
int i, err;
for (i = 0; i < AF9015_MAX_VIRTUAL_ADAPTERS; i++) {
printk("%s: Initializing adapter %d\n", __func__, i);
mutex_init(&biu->biu_lock);
memcpy(i2c, &af9015_i2c_adapter[i], sizeof (struct
i2c_adapter));
i2c_set_adapdata(i2c, biu);
i2c->dev.parent = &biu->udev->udev->dev;
if ((err = i2c_add_adapter(i2c)) < 0) {
printk("%s: Adapter %d init failed\n", __func__, i);
goto exit;
}
i2c++;
}
printk("%s: Initializing Virtual adapters\n", __func__);
return 0;
exit:
return err;
}
int __devexit af9015_i2c_exit(struct af901x_biu *biu)
{
struct i2c_adapter *i2c = biu->adapter;
int i, err;
for (i = 0; i < AF9015_MAX_VIRTUAL_ADAPTERS; i++) {
err = i2c_del_adapter(i2c);
i2c++;
}
return 0;
}
/*
AF-9015 Bus Interface Unit driver
Copyright (c) Manu Abraham <[EMAIL PROTECTED]>
Copyright (c) AFA Technologies
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.
*/
#ifndef __AF9015_PRIV_H
#define __AF9015_PRIV_H
#include <linux/usb.h>
#include "af9015.h"
enum af9015_tuner_types {
AF9015_TUNER_MT2060D = 130,
AF9015_TUNER_MXL5003D = 3,
AF9015_TUNER_MXL5005H = 13,
#if 0
AF9015_TUNER_QT1010 = xxx
AF9015_TUNER_MC44S802 = xxx
AF9015_TUNER_MC44S803 = xxx
#endif
};
enum af9015_ir_types {
AF9015_IR_NEC = 0,
AF9015_IR_RC6,
};
enum af9015_ir_mode {
AF9015_IRMODE_DISABLED = 0,
AF9015_IRMODE_HID,
AF9015_IRMODE_RLC,
AF9015_IRMODE_RC6
};
/**
* Mode 15: Used normally in PC applications
* either USB mode or SERIAL mode
* Mode 17: Used in consumer devices with a MPEG decoder
* USB mode alongwith a SERIAL mode
*/
enum af9015_biu_mode {
AF9015_BIU_MODE_15 = 1,
AF9015_BIU_MODE_17
};
/**
* Mode 11: USB 1.1 mode application
* Mode 20: USB 2.0 mode application
*/
enum af9015_usb_mode {
AF9015_USB_MODE_11 = 1,
AF9015_USB_MODE_20
};
struct af901x_biu_config { // will change it state (biu_state)
struct af901x_state *state;
// u8 ir_mode; /* from EEPROM, must go out */
enum af9015_ir_mode ir_mode;
u8 ts_mode; /* from EEPROM, must go out */
u8 addr;
u8 saw_bw; /* from EEPROM, must go out */
u8 osc_type; /*from EEPROM, must go out */
enum af9015_tuner_types tuner; /* from EEPROM, must go out */
enum af9015_ir_types ir_type; /* from EEPROM, must go out */
u32 osc_freq; /* from EEPROM, must go out */
u16 i_freq_0; /* IF 1 */ /* from EEPROM, must go out */
u16 i_freq_1; /* IF 2 */ /* from EEPROM, must go out */
u8 inversion; /* from EEPROM, must go out */
// u8 usb_11; // This is static
};
struct af9015_biuconfig_mode {
enum af9015_biu_mode biu_mode;
enum af9015_usb_mode usb_mode;
};
struct af901x_biu {
struct dvb_usb_adapter *usb_adapter;
struct dvb_usb_device *udev;
struct i2c_adapter *i2c; /* we are in the real world */
struct mutex biu_lock;
struct i2c_adapter adapter[2]; /* explore virtual worlds */
struct af901x_state *state;
struct af901x_config *dmd_config;
struct af901x_biu_config biu_config;
struct af9015_biuconfig_mode config_mode;
u8 biu_seq;
};
enum af9015_biu_cmd {
AF9015_REQ_CURCONFIG = 0x10, /* 1a) Get current config */
AF9015_REQ_FWDOWNLOAD = 0x11, /* 2a) Download Firmware
control messages */
AF9015_REQ_CHKSUMCOMPUTE = 0x12, /* 3a) Calculate Checksum
control messages */
AF9015_REQ_BOOTCONTROL = 0x13, /* 4a) Boot control messages */
AF9015_REQ_BIUMMIO_RD = 0x20, /* 5a) USB Memory RD control
messages */
AF9015_REQ_BIUMMIO_WR = 0x21, /* 6a) USB Memory WR control
messages */
AF9015_REQ_GENERIC_I2C = 0x22, /* 7a) General I2C control
messages */
AF9015_REQ_FWCOPY = 0x23, /* 8a) Copy Firmware control
messages */
AF9015_REQ_FWVERSION = 0x24,
AF9015_REQ_SWRESET = 0x25, /* 9) Software reset control
messages */
AF9015_REQ_CMDCTL = 0x26, /* 10a) Control unit command
conrtol messages */
AF9015_REQ_PROPRIETARY_IR = 0x27,
AF9015_REQ_FWRELINK = 0x5a
};
struct af9015_biu_msg {
u16 addr; /* Slave address */
enum af9015_biu_cmd biu_cmd; /* Command */
// u8 sequence; // for read
u8 reg_addr_msb; // Temporary
u8 reg_addr_lsb; // Temporary
u8 addr_length; /* page offset */
u16 flags;
#define BIU_RD 0x01
u8 *data; /* Data */
u16 length; /* Length of data */
};
#define AF9015_ERROR 0
#define AF9015_NOTICE 1
#define AF9015_INFO 2
#define AF9015_DEBUG 3
#define dprint(x, y, z, format, arg...) do {
\
if (z) {
\
if ((x > AF9015_ERROR) && (x > y))
\
printk(AF9015_ERR "%s (%d): " format "\n", __func__,
state->num, ##arg);\
else if ((x > AF9015_NOTICE) && (x > y))
\
printk(AF9015_ERR "%s (%d): " format "\n", __func__,
state->num, ##arg);\
else if ((x > AF9015_INFO) && (x > y))
\
printk(AF9015_ERR "%s (%d): " format "\n", __func__,
state->num, ##arg);\
else if ((x > AF9015_DEBUG) && (x > y))
\
printk(AF9015_ERR "%s (%d): " format "\n", __func__,
state->num, ##arg);\
} else {
\
if (x > y)
\
printk(format, ##arg);
\
}
\
} while (0);
#define AF901x_GETFIELD(bitf, val) ((val >> AF901x_OFFST_##bitf) & \
((1 << AF901x_WIDTH_##bitf) - 1))
#define AF901x_SETFIELD(bitf, mask, val)(mask = (mask & (~(((1 <<
AF901x_WIDTH_##bitf) - 1)<< \
AF901x_OFFST_##bitf)))
| (val << AF901x_OFFST_##bitf))
struct af901x_reg {
u16 reg_addr;
u8 pos;
u8 len;
u8 val;
};
#define AF901x_SLAVE_DEMOD_ADDR 0x3a
#define MERC_ADDR_FW_VER 0x5103
#define MERC_IR_TABLE_BASE_ADDR 0x9A56
#define MERC_ADDR_HW_VER 0x116B
#define AF901X_API_VER_0 0
#define AF901X_API_VER_1 1
#define AF901X_API_VER_2 9
#define AF901X_API_VER_3 0
extern int af9015_biu_xfer(struct usb_device *udev, struct af9015_biu_msg
*msgs, int num);
extern int af9015_i2c_exit(struct af901x_biu *biu);
extern int af9015_i2c_init(struct af901x_biu *biu);
extern int af9015_biu_read(struct usb_device *udev, struct af9015_biu_msg *msg);
extern int af9015_biu_write(struct usb_device *udev, struct af9015_biu_msg
*msg);
#endif//__AF9015_PRIV_H
_______________________________________________
linux-dvb mailing list
[email protected]
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb