/* AF-9015 Bus Interface Unit driver Copyright (c) Manu Abraham 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 #include #include #include #include #include "af9015_priv.h" #include "dvb-usb.h" #include /** * 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; }