📄 af9015.c
字号:
/* * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver * * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> * * Thanks to Afatech who kindly provided information. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "af9015.h"#include "af9013.h"#include "mt2060.h"#include "qt1010.h"#include "tda18271.h"#include "mxl5005s.h"#if 0 /* keep */#include "mc44s80x.h"#endifint dvb_usb_af9015_debug;module_param_named(debug, dvb_usb_af9015_debug, int, 0644);MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);int dvb_usb_af9015_remote;module_param_named(remote, dvb_usb_af9015_remote, int, 0644);MODULE_PARM_DESC(remote, "select remote");int dvb_usb_af9015_dual_mode;module_param_named(dual_mode, dvb_usb_af9015_dual_mode, int, 0644);MODULE_PARM_DESC(dual_mode, "enable dual mode");DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);static DEFINE_MUTEX(af9015_usb_mutex);static struct af9015_config af9015_config;static struct dvb_usb_device_properties af9015_properties[2];int af9015_properties_count = ARRAY_SIZE(af9015_properties);static struct af9013_config af9015_af9013_config[] = { { .demod_address = AF9015_I2C_DEMOD, .output_mode = AF9013_OUTPUT_MODE_USB, .api_version = { 0, 1, 9, 0 }, .gpio[0] = AF9013_GPIO_HI, .gpio[3] = AF9013_GPIO_TUNER_ON, }, { .output_mode = AF9013_OUTPUT_MODE_SERIAL, .api_version = { 0, 1, 9, 0 }, .gpio[0] = AF9013_GPIO_TUNER_ON, .gpio[1] = AF9013_GPIO_LO, }};static int af9015_rw_udev(struct usb_device *udev, struct req_t *req){ int act_len, ret; u8 buf[64]; u8 write = 1; u8 msg_len = 8; static u8 seq; /* packet sequence number */ if (mutex_lock_interruptible(&af9015_usb_mutex) < 0) return -EAGAIN; buf[0] = req->cmd; buf[1] = seq++; buf[2] = req->i2c_addr; buf[3] = req->addr >> 8; buf[4] = req->addr & 0xff; buf[5] = req->mbox; buf[6] = req->addr_len; buf[7] = req->data_len; switch (req->cmd) { case GET_CONFIG: case BOOT: case READ_MEMORY: case RECONNECT_USB: case GET_IR_CODE: write = 0; break; case READ_I2C: write = 0; buf[2] |= 0x01; /* set I2C direction */ case WRITE_I2C: buf[0] = READ_WRITE_I2C; break; case WRITE_MEMORY: if (((req->addr & 0xff00) == 0xff00) || ((req->addr & 0xae00) == 0xae00)) buf[0] = WRITE_VIRTUAL_MEMORY; case WRITE_VIRTUAL_MEMORY: case COPY_FIRMWARE: case DOWNLOAD_FIRMWARE: break; default: err("unknown command:%d", req->cmd); ret = -1; goto error_unlock; } /* write requested */ if (write) { memcpy(&buf[8], req->data, req->data_len); msg_len += req->data_len; } deb_xfer(">>> "); debug_dump(buf, msg_len, deb_xfer); /* send req */ ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, &act_len, AF9015_USB_TIMEOUT); if (ret) err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len); else if (act_len != msg_len) ret = -1; /* all data is not send */ if (ret) goto error_unlock; /* no ack for those packets */ if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) goto exit_unlock; /* receive ack and data if read req */ msg_len = 1 + 1 + req->data_len; /* seq + status + data len */ ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, &act_len, AF9015_USB_TIMEOUT); if (ret) { err("recv bulk message failed:%d", ret); ret = -1; goto error_unlock; } deb_xfer("<<< "); debug_dump(buf, act_len, deb_xfer); /* remote controller query status is 1 if remote code is not received */ if (req->cmd == GET_IR_CODE && buf[1] == 1) { buf[1] = 0; /* clear command "error" status */ memset(&buf[2], 0, req->data_len); buf[3] = 1; /* no remote code received mark */ } /* check status */ if (buf[1]) { err("command failed:%d", buf[1]); ret = -1; goto error_unlock; } /* read request, copy returned data to return buf */ if (!write) memcpy(req->data, &buf[2], req->data_len);error_unlock:exit_unlock: mutex_unlock(&af9015_usb_mutex); return ret;}static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req){ return af9015_rw_udev(d->udev, req);}static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len){ struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, val}; return af9015_ctrl_msg(d, &req);}static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val){ return af9015_write_regs(d, addr, &val, 1);}static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val){ struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, 1, val}; return af9015_ctrl_msg(d, &req);}static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, u8 val){ struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; if (addr == af9015_af9013_config[0].demod_address || addr == af9015_af9013_config[1].demod_address) req.addr_len = 3; return af9015_ctrl_msg(d, &req);}static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, u8 *val){ struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; if (addr == af9015_af9013_config[0].demod_address || addr == af9015_af9013_config[1].demod_address) req.addr_len = 3; return af9015_ctrl_msg(d, &req);}static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num){ struct dvb_usb_device *d = i2c_get_adapdata(adap); int ret = 0, i = 0; u16 addr; u8 mbox, addr_len; struct req_t req;/* TODO: implement bus lockThe bus lock is needed because there is two tuners both using same I2C-address.Due to that the only way to select correct tuner is use demodulator I2C-gate.................................................. AF9015 includes integrated AF9013 demodulator.. ____________ ____________ . ____________.| uC | | demod | . | tuner |.|------------| |------------| . |------------|.| AF9015 | | AF9013/5 | . | MXL5003 |.| |--+----I2C-------|-----/ -----|-.-----I2C-------| |.| | | | addr 0x38 | . | addr 0xc6 |.|____________| | |____________| . |____________|.................|.............................. | ____________ ____________ | | demod | | tuner | | |------------| |------------| | | AF9013 | | MXL5003 | +----I2C-------|-----/ -----|-------I2C-------| | | addr 0x3a | | addr 0xc6 | |____________| |____________|*/ if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; while (i < num) { if (msg[i].addr == af9015_af9013_config[0].demod_address || msg[i].addr == af9015_af9013_config[1].demod_address) { addr = msg[i].buf[0] << 8; addr += msg[i].buf[1]; mbox = msg[i].buf[2]; addr_len = 3; } else { addr = msg[i].buf[0]; addr_len = 1; mbox = 0; } if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { if (msg[i].addr == af9015_af9013_config[0].demod_address) req.cmd = READ_MEMORY; else req.cmd = READ_I2C; req.i2c_addr = msg[i].addr; req.addr = addr; req.mbox = mbox; req.addr_len = addr_len; req.data_len = msg[i+1].len; req.data = &msg[i+1].buf[0]; ret = af9015_ctrl_msg(d, &req); i += 2; } else { if (msg[i].addr == af9015_af9013_config[0].demod_address) req.cmd = WRITE_MEMORY; else req.cmd = WRITE_I2C; req.i2c_addr = msg[i].addr; req.addr = addr; req.mbox = mbox; req.addr_len = addr_len; req.data_len = msg[i].len-addr_len; req.data = &msg[i].buf[addr_len]; ret = af9015_ctrl_msg(d, &req); i += 1; } if (ret) goto error; } ret = i;error: mutex_unlock(&d->i2c_mutex); return ret;}static u32 af9015_i2c_func(struct i2c_adapter *adapter){ return I2C_FUNC_I2C;}static struct i2c_algorithm af9015_i2c_algo = { .master_xfer = af9015_i2c_xfer, .functionality = af9015_i2c_func,};static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op){ int ret; u8 val, mask = 0x01; ret = af9015_read_reg(d, addr, &val); if (ret) return ret; mask <<= bit; if (op) { /* set bit */ val |= mask; } else { /* clear bit */ mask ^= 0xff; val &= mask; } return af9015_write_reg(d, addr, val);}static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit){ return af9015_do_reg_bit(d, addr, bit, 1);}static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit){ return af9015_do_reg_bit(d, addr, bit, 0);}static int af9015_init_endpoint(struct dvb_usb_device *d){ int ret; u16 frame_size; u8 packet_size; deb_info("%s: USB speed:%d\n", __func__, d->udev->speed);#define TS_PACKET_SIZE 188#define TS_USB20_PACKET_COUNT 348#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT)#define TS_USB11_PACKET_COUNT 21#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT)#define TS_USB20_MAX_PACKET_SIZE 512#define TS_USB11_MAX_PACKET_SIZE 64 if (d->udev->speed == USB_SPEED_FULL) { frame_size = TS_USB11_FRAME_SIZE/4; packet_size = TS_USB11_MAX_PACKET_SIZE/4; } else { frame_size = TS_USB20_FRAME_SIZE/4; packet_size = TS_USB20_MAX_PACKET_SIZE/4; } ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ if (ret) goto error; ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ if (ret) goto error; ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ if (ret) goto error; ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ if (ret) goto error; ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ if (ret) goto error; if (af9015_config.dual_mode) { ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ if (ret) goto error; } ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ if (ret) goto error; if (af9015_config.dual_mode) { ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ if (ret) goto error; } /* EP4 xfer length */ ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); if (ret) goto error; ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); if (ret) goto error; /* EP5 xfer length */ ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); if (ret) goto error; ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); if (ret) goto error; ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ if (ret) goto error; ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ if (ret) goto error; ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ if (ret) goto error; if (af9015_config.dual_mode) { ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ if (ret) goto error; } /* enable / disable mp2if2 */ if (af9015_config.dual_mode) ret = af9015_set_reg_bit(d, 0xd50b, 0); else ret = af9015_clear_reg_bit(d, 0xd50b, 0);error: if (ret) err("endpoint init failed:%d", ret); return ret;}static int af9015_copy_firmware(struct dvb_usb_device *d){ int ret; u8 fw_params[4]; u8 val, i; struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), fw_params }; deb_info("%s:\n", __func__); fw_params[0] = af9015_config.firmware_size >> 8; fw_params[1] = af9015_config.firmware_size & 0xff; fw_params[2] = af9015_config.firmware_checksum >> 8; fw_params[3] = af9015_config.firmware_checksum & 0xff; /* wait 2nd demodulator ready */ msleep(100); ret = af9015_read_reg_i2c(d, 0x3a, 0x98be, &val); if (ret) goto error; else deb_info("%s: firmware status:%02x\n", __func__, val); if (val == 0x0c) /* fw is running, no need for download */ goto exit; /* set I2C master clock to fast (to speed up firmware copy) */ ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ if (ret) goto error; msleep(50); /* copy firmware */ ret = af9015_ctrl_msg(d, &req); if (ret) err("firmware copy cmd failed:%d", ret); deb_info("%s: firmware copy done\n", __func__); /* set I2C master clock back to normal */ ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ if (ret) goto error; /* request boot firmware */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -