Re: bus control

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>> 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 <abraham.manu@xxxxxxxxx>
	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 <abraham.manu@xxxxxxxxx>
	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 <abraham.manu@xxxxxxxxx>
	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, &reg);
	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, &reg);
	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, &reg);
	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, &reg);
	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, &reg);
	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, &reg);
		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, &reg);
		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, &reg);
	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, &reg); /* 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, &reg);
		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, &reg); /* 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, &reg);
	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, &reg); /* 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, &reg);
		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, &reg);
	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, &reg);
		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, &reg);
		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, &reg);
		AF901x_SETFIELD(MP2IF_3_EN, reg, 0); /* disable MP2IF */
		af9015_write(v_bus, AF901x_MP2IF_3, reg);
	}
	af9015_read(v_bus, AF901x_MP2IF_2, &reg);
	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, &reg);
	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, &reg);
		/* change output bit to Data 7, for the AF9013 */
		if (!(AF901x_GETFIELD(MP2IF_USB20_MODE, reg))) {
			af9015_read(v_bus, AF901x_MP2IF_0, &reg);
			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, &reg);
		AF901x_SETFIELD(MP2IF_3_HALF_PSB, reg, 1);
		af9015_write(v_bus, AF901x_MP2IF_3, reg);

		af9015_read(v_bus, AF901x_TSPARAM, &reg);
		AF901x_SETFIELD(TSPARAM_STOP_EN, reg, 1);
		af9015_write(v_bus, AF901x_TSPARAM, reg);

		af9015_read(v_bus, AF901x_MPEG_FULL_SPEED, &reg);
		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, &reg);
	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, &reg);
	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, &reg);
	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, &reg);
	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, &reg); /* 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, &reg);
	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, &reg);
	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, &reg); /* 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, &reg); /* 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, &reg);
	AF901x_SETFIELD(MP2IF_3_EN, reg, 1); /* enable MP2IF */
	af9015_write(v_bus, AF901x_MP2IF_3, reg);

	af9015_read(v_bus, AF901x_MP2IF_3, &reg);
	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 <linux-dvb@xxxxxxxxxxx>\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 <abraham.manu@xxxxxxxxx>");
MODULE_DESCRIPTION("AF9015 DVB-T");
MODULE_LICENSE("GPL");
/*
	AF-9015 Bus Interface Unit driver

	Copyright (c) Manu Abraham <abraham.manu@xxxxxxxxx>
	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 <abraham.manu@xxxxxxxxx>
	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
linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux