mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-10-29 15:28:50 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
150
drivers/media/usb/dvb-usb-v2/Kconfig
Normal file
150
drivers/media/usb/dvb-usb-v2/Kconfig
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
config DVB_USB_V2
|
||||
tristate "Support for various USB DVB devices v2"
|
||||
depends on DVB_CORE && USB && I2C && (RC_CORE || RC_CORE=n)
|
||||
help
|
||||
By enabling this you will be able to choose the various supported
|
||||
USB1.1 and USB2.0 DVB devices.
|
||||
|
||||
Almost every USB device needs a firmware, please look into
|
||||
<file:Documentation/dvb/README.dvb-usb>.
|
||||
|
||||
For a complete list of supported USB devices see the LinuxTV DVB Wiki:
|
||||
<http://www.linuxtv.org/wiki/index.php/DVB_USB>
|
||||
|
||||
Say Y if you own a USB DVB device.
|
||||
|
||||
config DVB_USB_AF9015
|
||||
tristate "Afatech AF9015 DVB-T USB2.0 support"
|
||||
depends on DVB_USB_V2
|
||||
select DVB_AF9013
|
||||
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MC44S803 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_TDA18218 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
|
||||
|
||||
config DVB_USB_AF9035
|
||||
tristate "Afatech AF9035 DVB-T USB2.0 support"
|
||||
depends on DVB_USB_V2
|
||||
select DVB_AF9033
|
||||
select MEDIA_TUNER_TUA9001 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_FC0011 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_TDA18218 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_IT913X if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the Afatech AF9035 based DVB USB receiver.
|
||||
|
||||
config DVB_USB_ANYSEE
|
||||
tristate "Anysee DVB-T/C USB2.0 support"
|
||||
depends on DVB_USB_V2
|
||||
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_ISL6423 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CXD2820R if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the Anysee E30, Anysee E30 Plus or
|
||||
Anysee E30 C Plus DVB USB2.0 receiver.
|
||||
|
||||
config DVB_USB_AU6610
|
||||
tristate "Alcor Micro AU6610 USB2.0 support"
|
||||
depends on DVB_USB_V2
|
||||
select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
|
||||
|
||||
config DVB_USB_AZ6007
|
||||
tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support"
|
||||
depends on DVB_USB_V2
|
||||
select CYPRESS_FIRMWARE
|
||||
select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the AZ6007 receivers like Terratec H7.
|
||||
|
||||
config DVB_USB_CE6230
|
||||
tristate "Intel CE6230 DVB-T USB2.0 support"
|
||||
depends on DVB_USB_V2
|
||||
select DVB_ZL10353
|
||||
select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver
|
||||
|
||||
config DVB_USB_EC168
|
||||
tristate "E3C EC168 DVB-T USB2.0 support"
|
||||
depends on DVB_USB_V2
|
||||
select DVB_EC100
|
||||
select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
|
||||
|
||||
config DVB_USB_GL861
|
||||
tristate "Genesys Logic GL861 USB2.0 support"
|
||||
depends on DVB_USB_V2
|
||||
select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
|
||||
receiver with USB ID 0db0:5581.
|
||||
|
||||
config DVB_USB_LME2510
|
||||
tristate "LME DM04/QQBOX DVB-S USB2.0 support"
|
||||
depends on DVB_USB_V2
|
||||
depends on RC_CORE
|
||||
select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_IX2505V if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_M88RS2000 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the LME DM04/QQBOX DVB-S USB2.0
|
||||
|
||||
config DVB_USB_MXL111SF
|
||||
tristate "MxL111SF DTV USB2.0 support"
|
||||
depends on DVB_USB_V2
|
||||
select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_LG2160 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select VIDEO_TVEEPROM
|
||||
help
|
||||
Say Y here to support the MxL111SF USB2.0 DTV receiver.
|
||||
|
||||
config DVB_USB_RTL28XXU
|
||||
tristate "Realtek RTL28xxU DVB USB support"
|
||||
depends on DVB_USB_V2 && I2C_MUX
|
||||
select DVB_RTL2830
|
||||
select DVB_RTL2832
|
||||
select DVB_RTL2832_SDR if (MEDIA_SUBDRV_AUTOSELECT && MEDIA_SDR_SUPPORT)
|
||||
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_FC0012 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_FC0013 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_E4000 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_R820T if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the Realtek RTL28xxU DVB USB receiver.
|
||||
|
||||
config DVB_USB_DVBSKY
|
||||
tristate "DVBSky USB support"
|
||||
depends on DVB_USB_V2
|
||||
select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the USB receivers from DVBSky.
|
||||
46
drivers/media/usb/dvb-usb-v2/Makefile
Normal file
46
drivers/media/usb/dvb-usb-v2/Makefile
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
dvb_usb_v2-objs := dvb_usb_core.o dvb_usb_urb.o usb_urb.o
|
||||
obj-$(CONFIG_DVB_USB_V2) += dvb_usb_v2.o
|
||||
|
||||
dvb-usb-af9015-objs := af9015.o
|
||||
obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
|
||||
|
||||
dvb-usb-af9035-objs := af9035.o
|
||||
obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o
|
||||
|
||||
dvb-usb-anysee-objs := anysee.o
|
||||
obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
|
||||
|
||||
dvb-usb-au6610-objs := au6610.o
|
||||
obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o
|
||||
|
||||
dvb-usb-az6007-objs := az6007.o
|
||||
obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o
|
||||
|
||||
dvb-usb-ce6230-objs := ce6230.o
|
||||
obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
|
||||
|
||||
dvb-usb-ec168-objs := ec168.o
|
||||
obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
|
||||
|
||||
dvb-usb-lmedm04-objs := lmedm04.o
|
||||
obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
|
||||
|
||||
dvb-usb-gl861-objs := gl861.o
|
||||
obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o
|
||||
|
||||
dvb-usb-mxl111sf-objs += mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o
|
||||
dvb-usb-mxl111sf-objs += mxl111sf-gpio.o
|
||||
obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o
|
||||
obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o
|
||||
obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
|
||||
|
||||
dvb-usb-rtl28xxu-objs := rtl28xxu.o
|
||||
obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
|
||||
|
||||
dvb-usb-dvbsky-objs := dvbsky.o
|
||||
obj-$(CONFIG_DVB_USB_DVBSKY) += dvb-usb-dvbsky.o
|
||||
|
||||
ccflags-y += -I$(srctree)/drivers/media/dvb-core
|
||||
ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
|
||||
ccflags-y += -I$(srctree)/drivers/media/tuners
|
||||
ccflags-y += -I$(srctree)/drivers/media/common
|
||||
1504
drivers/media/usb/dvb-usb-v2/af9015.c
Normal file
1504
drivers/media/usb/dvb-usb-v2/af9015.c
Normal file
File diff suppressed because it is too large
Load diff
153
drivers/media/usb/dvb-usb-v2/af9015.h
Normal file
153
drivers/media/usb/dvb-usb-v2/af9015.h
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AF9015_H
|
||||
#define AF9015_H
|
||||
|
||||
#include <linux/hash.h>
|
||||
#include "dvb_usb.h"
|
||||
#include "af9013.h"
|
||||
#include "dvb-pll.h"
|
||||
#include "mt2060.h"
|
||||
#include "qt1010.h"
|
||||
#include "tda18271.h"
|
||||
#include "mxl5005s.h"
|
||||
#include "mc44s803.h"
|
||||
#include "tda18218.h"
|
||||
#include "mxl5007t.h"
|
||||
|
||||
#define AF9015_FIRMWARE "dvb-usb-af9015.fw"
|
||||
|
||||
/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0.
|
||||
We use smaller - about 1/4 from the original, 5 and 87. */
|
||||
#define TS_PACKET_SIZE 188
|
||||
|
||||
#define TS_USB20_PACKET_COUNT 87
|
||||
#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT)
|
||||
|
||||
#define TS_USB11_PACKET_COUNT 5
|
||||
#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
|
||||
|
||||
#define AF9015_I2C_EEPROM 0xa0
|
||||
#define AF9015_I2C_DEMOD 0x38
|
||||
#define AF9015_USB_TIMEOUT 2000
|
||||
|
||||
/* EEPROM locations */
|
||||
#define AF9015_EEPROM_IR_MODE 0x18
|
||||
#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34
|
||||
#define AF9015_EEPROM_TS_MODE 0x31
|
||||
#define AF9015_EEPROM_DEMOD2_I2C 0x32
|
||||
|
||||
#define AF9015_EEPROM_SAW_BW1 0x35
|
||||
#define AF9015_EEPROM_XTAL_TYPE1 0x36
|
||||
#define AF9015_EEPROM_SPEC_INV1 0x37
|
||||
#define AF9015_EEPROM_IF1L 0x38
|
||||
#define AF9015_EEPROM_IF1H 0x39
|
||||
#define AF9015_EEPROM_MT2060_IF1L 0x3a
|
||||
#define AF9015_EEPROM_MT2060_IF1H 0x3b
|
||||
#define AF9015_EEPROM_TUNER_ID1 0x3c
|
||||
|
||||
#define AF9015_EEPROM_SAW_BW2 0x45
|
||||
#define AF9015_EEPROM_XTAL_TYPE2 0x46
|
||||
#define AF9015_EEPROM_SPEC_INV2 0x47
|
||||
#define AF9015_EEPROM_IF2L 0x48
|
||||
#define AF9015_EEPROM_IF2H 0x49
|
||||
#define AF9015_EEPROM_MT2060_IF2L 0x4a
|
||||
#define AF9015_EEPROM_MT2060_IF2H 0x4b
|
||||
#define AF9015_EEPROM_TUNER_ID2 0x4c
|
||||
|
||||
#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1)
|
||||
|
||||
struct req_t {
|
||||
u8 cmd; /* [0] */
|
||||
/* seq */ /* [1] */
|
||||
u8 i2c_addr; /* [2] */
|
||||
u16 addr; /* [3|4] */
|
||||
u8 mbox; /* [5] */
|
||||
u8 addr_len; /* [6] */
|
||||
u8 data_len; /* [7] */
|
||||
u8 *data;
|
||||
};
|
||||
|
||||
enum af9015_cmd {
|
||||
GET_CONFIG = 0x10,
|
||||
DOWNLOAD_FIRMWARE = 0x11,
|
||||
BOOT = 0x13,
|
||||
READ_MEMORY = 0x20,
|
||||
WRITE_MEMORY = 0x21,
|
||||
READ_WRITE_I2C = 0x22,
|
||||
COPY_FIRMWARE = 0x23,
|
||||
RECONNECT_USB = 0x5a,
|
||||
WRITE_VIRTUAL_MEMORY = 0x26,
|
||||
GET_IR_CODE = 0x27,
|
||||
READ_I2C,
|
||||
WRITE_I2C,
|
||||
};
|
||||
|
||||
enum af9015_ir_mode {
|
||||
AF9015_IR_MODE_DISABLED = 0,
|
||||
AF9015_IR_MODE_HID,
|
||||
AF9015_IR_MODE_RLC,
|
||||
AF9015_IR_MODE_RC6,
|
||||
AF9015_IR_MODE_POLLING, /* just guess */
|
||||
};
|
||||
|
||||
#define BUF_LEN 63
|
||||
struct af9015_state {
|
||||
u8 buf[BUF_LEN]; /* bulk USB control message */
|
||||
u8 ir_mode;
|
||||
u8 rc_repeat;
|
||||
u32 rc_keycode;
|
||||
u8 rc_last[4];
|
||||
bool rc_failed;
|
||||
u8 dual_mode;
|
||||
u8 seq; /* packet sequence number */
|
||||
u16 mt2060_if1[2];
|
||||
u16 firmware_size;
|
||||
u16 firmware_checksum;
|
||||
u32 eeprom_sum;
|
||||
struct af9013_config af9013_config[2];
|
||||
|
||||
/* for demod callback override */
|
||||
int (*set_frontend[2]) (struct dvb_frontend *fe);
|
||||
int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status);
|
||||
int (*init[2]) (struct dvb_frontend *fe);
|
||||
int (*sleep[2]) (struct dvb_frontend *fe);
|
||||
int (*tuner_init[2]) (struct dvb_frontend *fe);
|
||||
int (*tuner_sleep[2]) (struct dvb_frontend *fe);
|
||||
struct mutex fe_mutex;
|
||||
};
|
||||
|
||||
enum af9015_remote {
|
||||
AF9015_REMOTE_NONE = 0,
|
||||
/* 1 */ AF9015_REMOTE_A_LINK_DTU_M,
|
||||
AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
|
||||
AF9015_REMOTE_MYGICTV_U718,
|
||||
AF9015_REMOTE_DIGITTRADE_DVB_T,
|
||||
/* 5 */ AF9015_REMOTE_AVERMEDIA_KS,
|
||||
};
|
||||
|
||||
#endif
|
||||
2087
drivers/media/usb/dvb-usb-v2/af9035.c
Normal file
2087
drivers/media/usb/dvb-usb-v2/af9035.c
Normal file
File diff suppressed because it is too large
Load diff
150
drivers/media/usb/dvb-usb-v2/af9035.h
Normal file
150
drivers/media/usb/dvb-usb-v2/af9035.h
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Afatech AF9035 DVB USB driver
|
||||
*
|
||||
* Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
|
||||
* Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef AF9035_H
|
||||
#define AF9035_H
|
||||
|
||||
#include "dvb_usb.h"
|
||||
#include "af9033.h"
|
||||
#include "tua9001.h"
|
||||
#include "fc0011.h"
|
||||
#include "fc0012.h"
|
||||
#include "mxl5007t.h"
|
||||
#include "tda18218.h"
|
||||
#include "fc2580.h"
|
||||
#include "it913x.h"
|
||||
#include "si2168.h"
|
||||
#include "si2157.h"
|
||||
|
||||
struct reg_val {
|
||||
u32 reg;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
struct reg_val_mask {
|
||||
u32 reg;
|
||||
u8 val;
|
||||
u8 mask;
|
||||
};
|
||||
|
||||
struct usb_req {
|
||||
u8 cmd;
|
||||
u8 mbox;
|
||||
u8 wlen;
|
||||
u8 *wbuf;
|
||||
u8 rlen;
|
||||
u8 *rbuf;
|
||||
};
|
||||
|
||||
struct state {
|
||||
#define BUF_LEN 64
|
||||
u8 buf[BUF_LEN];
|
||||
u8 seq; /* packet sequence number */
|
||||
u8 prechip_version;
|
||||
u8 chip_version;
|
||||
u16 chip_type;
|
||||
u8 dual_mode:1;
|
||||
u16 eeprom_addr;
|
||||
u8 af9033_i2c_addr[2];
|
||||
struct af9033_config af9033_config[2];
|
||||
struct af9033_ops ops;
|
||||
#define AF9035_I2C_CLIENT_MAX 4
|
||||
struct i2c_client *i2c_client[AF9035_I2C_CLIENT_MAX];
|
||||
struct i2c_adapter *i2c_adapter_demod;
|
||||
};
|
||||
|
||||
static const u32 clock_lut_af9035[] = {
|
||||
20480000, /* FPGA */
|
||||
16384000, /* 16.38 MHz */
|
||||
20480000, /* 20.48 MHz */
|
||||
36000000, /* 36.00 MHz */
|
||||
30000000, /* 30.00 MHz */
|
||||
26000000, /* 26.00 MHz */
|
||||
28000000, /* 28.00 MHz */
|
||||
32000000, /* 32.00 MHz */
|
||||
34000000, /* 34.00 MHz */
|
||||
24000000, /* 24.00 MHz */
|
||||
22000000, /* 22.00 MHz */
|
||||
12000000, /* 12.00 MHz */
|
||||
};
|
||||
|
||||
static const u32 clock_lut_it9135[] = {
|
||||
12000000, /* 12.00 MHz */
|
||||
20480000, /* 20.48 MHz */
|
||||
36000000, /* 36.00 MHz */
|
||||
30000000, /* 30.00 MHz */
|
||||
26000000, /* 26.00 MHz */
|
||||
28000000, /* 28.00 MHz */
|
||||
32000000, /* 32.00 MHz */
|
||||
34000000, /* 34.00 MHz */
|
||||
24000000, /* 24.00 MHz */
|
||||
22000000, /* 22.00 MHz */
|
||||
};
|
||||
|
||||
#define AF9035_FIRMWARE_AF9035 "dvb-usb-af9035-02.fw"
|
||||
#define AF9035_FIRMWARE_IT9135_V1 "dvb-usb-it9135-01.fw"
|
||||
#define AF9035_FIRMWARE_IT9135_V2 "dvb-usb-it9135-02.fw"
|
||||
#define AF9035_FIRMWARE_IT9303 "dvb-usb-it9303-01.fw"
|
||||
|
||||
/*
|
||||
* eeprom is memory mapped as read only. Writing that memory mapped address
|
||||
* will not corrupt eeprom.
|
||||
*
|
||||
* TS mode:
|
||||
* 0 TS
|
||||
* 1 DCA + PIP
|
||||
* 3 PIP
|
||||
* n DCA
|
||||
*
|
||||
* Values 0 and 3 are seen to this day. 0 for single TS and 3 for dual TS.
|
||||
*/
|
||||
|
||||
#define EEPROM_BASE_AF9035 0x42fd
|
||||
#define EEPROM_BASE_IT9135 0x499c
|
||||
#define EEPROM_SHIFT 0x10
|
||||
|
||||
#define EEPROM_IR_MODE 0x10
|
||||
#define EEPROM_TS_MODE 0x29
|
||||
#define EEPROM_2ND_DEMOD_ADDR 0x2a
|
||||
#define EEPROM_IR_TYPE 0x2c
|
||||
#define EEPROM_1_IF_L 0x30
|
||||
#define EEPROM_1_IF_H 0x31
|
||||
#define EEPROM_1_TUNER_ID 0x34
|
||||
#define EEPROM_2_IF_L 0x40
|
||||
#define EEPROM_2_IF_H 0x41
|
||||
#define EEPROM_2_TUNER_ID 0x44
|
||||
|
||||
/* USB commands */
|
||||
#define CMD_MEM_RD 0x00
|
||||
#define CMD_MEM_WR 0x01
|
||||
#define CMD_I2C_RD 0x02
|
||||
#define CMD_I2C_WR 0x03
|
||||
#define CMD_IR_GET 0x18
|
||||
#define CMD_FW_DL 0x21
|
||||
#define CMD_FW_QUERYINFO 0x22
|
||||
#define CMD_FW_BOOT 0x23
|
||||
#define CMD_FW_DL_BEGIN 0x24
|
||||
#define CMD_FW_DL_END 0x25
|
||||
#define CMD_FW_SCATTER_WR 0x29
|
||||
#define CMD_GENERIC_I2C_RD 0x2a
|
||||
#define CMD_GENERIC_I2C_WR 0x2b
|
||||
|
||||
#endif
|
||||
1442
drivers/media/usb/dvb-usb-v2/anysee.c
Normal file
1442
drivers/media/usb/dvb-usb-v2/anysee.c
Normal file
File diff suppressed because it is too large
Load diff
330
drivers/media/usb/dvb-usb-v2/anysee.h
Normal file
330
drivers/media/usb/dvb-usb-v2/anysee.h
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
/*
|
||||
* DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
|
||||
*
|
||||
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* TODO:
|
||||
* - add smart card reader support for Conditional Access (CA)
|
||||
*
|
||||
* Card reader in Anysee is nothing more than ISO 7816 card reader.
|
||||
* There is no hardware CAM in any Anysee device sold.
|
||||
* In my understanding it should be implemented by making own module
|
||||
* for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
|
||||
* module registers serial interface that can be used to communicate
|
||||
* with any ISO 7816 smart card.
|
||||
*
|
||||
* Any help according to implement serial smart card reader support
|
||||
* is highly welcome!
|
||||
*/
|
||||
|
||||
#ifndef _DVB_USB_ANYSEE_H_
|
||||
#define _DVB_USB_ANYSEE_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "anysee"
|
||||
#include "dvb_usb.h"
|
||||
#include "dvb_ca_en50221.h"
|
||||
|
||||
enum cmd {
|
||||
CMD_I2C_READ = 0x33,
|
||||
CMD_I2C_WRITE = 0x31,
|
||||
CMD_REG_READ = 0xb0,
|
||||
CMD_REG_WRITE = 0xb1,
|
||||
CMD_STREAMING_CTRL = 0x12,
|
||||
CMD_LED_AND_IR_CTRL = 0x16,
|
||||
CMD_GET_IR_CODE = 0x41,
|
||||
CMD_GET_HW_INFO = 0x19,
|
||||
CMD_SMARTCARD = 0x34,
|
||||
CMD_CI = 0x37,
|
||||
};
|
||||
|
||||
struct anysee_state {
|
||||
u8 buf[64];
|
||||
u8 seq;
|
||||
u8 hw; /* PCB ID */
|
||||
#define ANYSEE_I2C_CLIENT_MAX 1
|
||||
struct i2c_client *i2c_client[ANYSEE_I2C_CLIENT_MAX];
|
||||
u8 fe_id:1; /* frondend ID */
|
||||
u8 has_ci:1;
|
||||
u8 has_tda18212:1;
|
||||
u8 ci_attached:1;
|
||||
struct dvb_ca_en50221 ci;
|
||||
unsigned long ci_cam_ready; /* jiffies */
|
||||
};
|
||||
|
||||
#define ANYSEE_HW_507T 2 /* E30 */
|
||||
#define ANYSEE_HW_507CD 6 /* E30 Plus */
|
||||
#define ANYSEE_HW_507DC 10 /* E30 C Plus */
|
||||
#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */
|
||||
#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */
|
||||
#define ANYSEE_HW_508TC 18 /* E7 TC */
|
||||
#define ANYSEE_HW_508S2 19 /* E7 S2 */
|
||||
#define ANYSEE_HW_508T2C 20 /* E7 T2C */
|
||||
#define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */
|
||||
#define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */
|
||||
|
||||
#define REG_IOA 0x80 /* Port A (bit addressable) */
|
||||
#define REG_IOB 0x90 /* Port B (bit addressable) */
|
||||
#define REG_IOC 0xa0 /* Port C (bit addressable) */
|
||||
#define REG_IOD 0xb0 /* Port D (bit addressable) */
|
||||
#define REG_IOE 0xb1 /* Port E (NOT bit addressable) */
|
||||
#define REG_OEA 0xb2 /* Port A Output Enable */
|
||||
#define REG_OEB 0xb3 /* Port B Output Enable */
|
||||
#define REG_OEC 0xb4 /* Port C Output Enable */
|
||||
#define REG_OED 0xb5 /* Port D Output Enable */
|
||||
#define REG_OEE 0xb6 /* Port E Output Enable */
|
||||
|
||||
#endif
|
||||
|
||||
/***************************************************************************
|
||||
* USB API description (reverse engineered)
|
||||
***************************************************************************
|
||||
|
||||
Transaction flow:
|
||||
=================
|
||||
BULK[00001] >>> REQUEST PACKET 64 bytes
|
||||
BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY)
|
||||
BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY)
|
||||
|
||||
General reply packet(s) are always used if not own reply defined.
|
||||
|
||||
============================================================================
|
||||
| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY)
|
||||
============================================================================
|
||||
| 00 | reply data (if any) from previous transaction
|
||||
| | Just same reply packet as returned during previous transaction.
|
||||
| | Needed only if reply is missed in previous transaction.
|
||||
| | Just skip normally.
|
||||
----------------------------------------------------------------------------
|
||||
| 01-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY)
|
||||
============================================================================
|
||||
| 00 | reply data (if any)
|
||||
----------------------------------------------------------------------------
|
||||
| 01-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | I2C WRITE REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x31 I2C write command
|
||||
----------------------------------------------------------------------------
|
||||
| 01 | i2c address
|
||||
----------------------------------------------------------------------------
|
||||
| 02 | data length
|
||||
| | 0x02 (for typical I2C reg / val pair)
|
||||
----------------------------------------------------------------------------
|
||||
| 03 | 0x01
|
||||
----------------------------------------------------------------------------
|
||||
| 04- | data
|
||||
----------------------------------------------------------------------------
|
||||
| -59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | I2C READ REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x33 I2C read command
|
||||
----------------------------------------------------------------------------
|
||||
| 01 | i2c address + 1
|
||||
----------------------------------------------------------------------------
|
||||
| 02 | register
|
||||
----------------------------------------------------------------------------
|
||||
| 03 | 0x00
|
||||
----------------------------------------------------------------------------
|
||||
| 04 | 0x00
|
||||
----------------------------------------------------------------------------
|
||||
| 05 | data length
|
||||
----------------------------------------------------------------------------
|
||||
| 06-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0xb1 register write command
|
||||
----------------------------------------------------------------------------
|
||||
| 01-02 | register
|
||||
----------------------------------------------------------------------------
|
||||
| 03 | 0x01
|
||||
----------------------------------------------------------------------------
|
||||
| 04 | value
|
||||
----------------------------------------------------------------------------
|
||||
| 05-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0xb0 register read command
|
||||
----------------------------------------------------------------------------
|
||||
| 01-02 | register
|
||||
----------------------------------------------------------------------------
|
||||
| 03 | 0x01
|
||||
----------------------------------------------------------------------------
|
||||
| 04-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | LED CONTROL REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x16 LED and IR control command
|
||||
----------------------------------------------------------------------------
|
||||
| 01 | 0x01 (LED)
|
||||
----------------------------------------------------------------------------
|
||||
| 03 | 0x00 blink
|
||||
| | 0x01 lights continuously
|
||||
----------------------------------------------------------------------------
|
||||
| 04 | blink interval
|
||||
| | 0x00 fastest (looks like LED lights continuously)
|
||||
| | 0xff slowest
|
||||
----------------------------------------------------------------------------
|
||||
| 05-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | IR CONTROL REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x16 LED and IR control command
|
||||
----------------------------------------------------------------------------
|
||||
| 01 | 0x02 (IR)
|
||||
----------------------------------------------------------------------------
|
||||
| 03 | 0x00 IR disabled
|
||||
| | 0x01 IR enabled
|
||||
----------------------------------------------------------------------------
|
||||
| 04-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | STREAMING CONTROL REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x12 streaming control command
|
||||
----------------------------------------------------------------------------
|
||||
| 01 | 0x00 streaming disabled
|
||||
| | 0x01 streaming enabled
|
||||
----------------------------------------------------------------------------
|
||||
| 02 | 0x00
|
||||
----------------------------------------------------------------------------
|
||||
| 03-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | REMOTE CONTROL REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x41 remote control command
|
||||
----------------------------------------------------------------------------
|
||||
| 01-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | REMOTE CONTROL REPLY PACKET
|
||||
============================================================================
|
||||
| 00 | 0x00 code not received
|
||||
| | 0x01 code received
|
||||
----------------------------------------------------------------------------
|
||||
| 01 | remote control code
|
||||
----------------------------------------------------------------------------
|
||||
| 02-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | GET HARDWARE INFO REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x19 get hardware info command
|
||||
----------------------------------------------------------------------------
|
||||
| 01-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | GET HARDWARE INFO REPLY PACKET
|
||||
============================================================================
|
||||
| 00 | hardware id
|
||||
----------------------------------------------------------------------------
|
||||
| 01-02 | firmware version
|
||||
----------------------------------------------------------------------------
|
||||
| 03-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | SMART CARD READER PACKET
|
||||
============================================================================
|
||||
| 00 | 0x34 smart card reader command
|
||||
----------------------------------------------------------------------------
|
||||
| xx |
|
||||
----------------------------------------------------------------------------
|
||||
| xx-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
*/
|
||||
213
drivers/media/usb/dvb-usb-v2/au6610.c
Normal file
213
drivers/media/usb/dvb-usb-v2/au6610.c
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
|
||||
*
|
||||
* Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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 "au6610.h"
|
||||
#include "zl10353.h"
|
||||
#include "qt1010.h"
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
int ret;
|
||||
u16 index;
|
||||
u8 *usb_buf;
|
||||
|
||||
/*
|
||||
* allocate enough for all known requests,
|
||||
* read returns 5 and write 6 bytes
|
||||
*/
|
||||
usb_buf = kmalloc(6, GFP_KERNEL);
|
||||
if (!usb_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (wlen) {
|
||||
case 1:
|
||||
index = wbuf[0] << 8;
|
||||
break;
|
||||
case 2:
|
||||
index = wbuf[0] << 8;
|
||||
index += wbuf[1];
|
||||
break;
|
||||
default:
|
||||
dev_err(&d->udev->dev, "%s: wlen=%d, aborting\n",
|
||||
KBUILD_MODNAME, wlen);
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
|
||||
USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,
|
||||
usb_buf, 6, AU6610_USB_TIMEOUT);
|
||||
|
||||
dvb_usb_dbg_usb_control_msg(d->udev, operation,
|
||||
(USB_TYPE_VENDOR|USB_DIR_IN), addr << 1, index,
|
||||
usb_buf, 6);
|
||||
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
switch (operation) {
|
||||
case AU6610_REQ_I2C_READ:
|
||||
case AU6610_REQ_USB_READ:
|
||||
/* requested value is always 5th byte in buffer */
|
||||
rbuf[0] = usb_buf[4];
|
||||
}
|
||||
error:
|
||||
kfree(usb_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u8 request;
|
||||
u8 wo = (rbuf == NULL || rlen == 0); /* write-only */
|
||||
|
||||
if (wo) {
|
||||
request = AU6610_REQ_I2C_WRITE;
|
||||
} else { /* rw */
|
||||
request = AU6610_REQ_I2C_READ;
|
||||
}
|
||||
|
||||
return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);
|
||||
}
|
||||
|
||||
|
||||
/* I2C */
|
||||
static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, msg[i+1].buf,
|
||||
msg[i+1].len) < 0)
|
||||
break;
|
||||
i++;
|
||||
} else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, NULL, 0) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static u32 au6610_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm au6610_i2c_algo = {
|
||||
.master_xfer = au6610_i2c_xfer,
|
||||
.functionality = au6610_i2c_func,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static struct zl10353_config au6610_zl10353_config = {
|
||||
.demod_address = 0x0f,
|
||||
.no_tuner = 1,
|
||||
.parallel_ts = 1,
|
||||
};
|
||||
|
||||
static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config,
|
||||
&adap_to_d(adap)->i2c_adap);
|
||||
if (adap->fe[0] == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct qt1010_config au6610_qt1010_config = {
|
||||
.i2c_address = 0x62
|
||||
};
|
||||
|
||||
static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
return dvb_attach(qt1010_attach, adap->fe[0],
|
||||
&adap_to_d(adap)->i2c_adap,
|
||||
&au6610_qt1010_config) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
static int au6610_init(struct dvb_usb_device *d)
|
||||
{
|
||||
/* TODO: this functionality belongs likely to the streaming control */
|
||||
/* bInterfaceNumber 0, bAlternateSetting 5 */
|
||||
return usb_set_interface(d->udev, 0, 5);
|
||||
}
|
||||
|
||||
static struct dvb_usb_device_properties au6610_props = {
|
||||
.driver_name = KBUILD_MODNAME,
|
||||
.owner = THIS_MODULE,
|
||||
.adapter_nr = adapter_nr,
|
||||
|
||||
.i2c_algo = &au6610_i2c_algo,
|
||||
.frontend_attach = au6610_zl10353_frontend_attach,
|
||||
.tuner_attach = au6610_qt1010_tuner_attach,
|
||||
.init = au6610_init,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.stream = DVB_USB_STREAM_ISOC(0x82, 5, 40, 942, 1),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct usb_device_id au6610_id_table[] = {
|
||||
{ DVB_USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110,
|
||||
&au6610_props, "Sigmatek DVB-110", NULL) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, au6610_id_table);
|
||||
|
||||
static struct usb_driver au6610_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = au6610_id_table,
|
||||
.probe = dvb_usbv2_probe,
|
||||
.disconnect = dvb_usbv2_disconnect,
|
||||
.suspend = dvb_usbv2_suspend,
|
||||
.resume = dvb_usbv2_resume,
|
||||
.reset_resume = dvb_usbv2_reset_resume,
|
||||
.no_dynamic_id = 1,
|
||||
.soft_unbind = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(au6610_driver);
|
||||
|
||||
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
|
||||
MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
||||
32
drivers/media/usb/dvb-usb-v2/au6610.h
Normal file
32
drivers/media/usb/dvb-usb-v2/au6610.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
|
||||
*
|
||||
* Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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 AU6610_H
|
||||
#define AU6610_H
|
||||
#include "dvb_usb.h"
|
||||
|
||||
#define AU6610_REQ_I2C_WRITE 0x14
|
||||
#define AU6610_REQ_I2C_READ 0x13
|
||||
#define AU6610_REQ_USB_WRITE 0x16
|
||||
#define AU6610_REQ_USB_READ 0x15
|
||||
|
||||
#define AU6610_USB_TIMEOUT 1000
|
||||
|
||||
#endif
|
||||
985
drivers/media/usb/dvb-usb-v2/az6007.c
Normal file
985
drivers/media/usb/dvb-usb-v2/az6007.c
Normal file
|
|
@ -0,0 +1,985 @@
|
|||
/*
|
||||
* Driver for AzureWave 6007 DVB-C/T USB2.0 and clones
|
||||
*
|
||||
* Copyright (c) Henry Wang <Henry.wang@AzureWave.com>
|
||||
*
|
||||
* This driver was made publicly available by Terratec, at:
|
||||
* http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
|
||||
* The original driver's license is GPL, as declared with MODULE_LICENSE()
|
||||
*
|
||||
* Copyright (c) 2010-2012 Mauro Carvalho Chehab
|
||||
* Driver modified by in order to work with upstream drxk driver, and
|
||||
* tons of bugs got fixed, and converted to use dvb-usb-v2.
|
||||
*
|
||||
* 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 under version 2 of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "drxk.h"
|
||||
#include "mt2063.h"
|
||||
#include "dvb_ca_en50221.h"
|
||||
#include "dvb_usb.h"
|
||||
#include "cypress_firmware.h"
|
||||
|
||||
#define AZ6007_FIRMWARE "dvb-usb-terratec-h7-az6007.fw"
|
||||
|
||||
static int az6007_xfer_debug;
|
||||
module_param_named(xfer_debug, az6007_xfer_debug, int, 0644);
|
||||
MODULE_PARM_DESC(xfer_debug, "Enable xfer debug");
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
/* Known requests (Cypress FX2 firmware + az6007 "private" ones*/
|
||||
|
||||
#define FX2_OED 0xb5
|
||||
#define AZ6007_READ_DATA 0xb7
|
||||
#define AZ6007_I2C_RD 0xb9
|
||||
#define AZ6007_POWER 0xbc
|
||||
#define AZ6007_I2C_WR 0xbd
|
||||
#define FX2_SCON1 0xc0
|
||||
#define AZ6007_TS_THROUGH 0xc7
|
||||
#define AZ6007_READ_IR 0xb4
|
||||
|
||||
struct az6007_device_state {
|
||||
struct mutex mutex;
|
||||
struct mutex ca_mutex;
|
||||
struct dvb_ca_en50221 ca;
|
||||
unsigned warm:1;
|
||||
int (*gate_ctrl) (struct dvb_frontend *, int);
|
||||
unsigned char data[4096];
|
||||
};
|
||||
|
||||
static struct drxk_config terratec_h7_drxk = {
|
||||
.adr = 0x29,
|
||||
.parallel_ts = true,
|
||||
.dynamic_clk = true,
|
||||
.single_master = true,
|
||||
.enable_merr_cfg = true,
|
||||
.no_i2c_bridge = false,
|
||||
.chunk_size = 64,
|
||||
.mpeg_out_clk_strength = 0x02,
|
||||
.qam_demod_parameter_count = 2,
|
||||
.microcode_name = "dvb-usb-terratec-h7-drxk.fw",
|
||||
};
|
||||
|
||||
static struct drxk_config cablestar_hdci_drxk = {
|
||||
.adr = 0x29,
|
||||
.parallel_ts = true,
|
||||
.dynamic_clk = true,
|
||||
.single_master = true,
|
||||
.enable_merr_cfg = true,
|
||||
.no_i2c_bridge = false,
|
||||
.chunk_size = 64,
|
||||
.mpeg_out_clk_strength = 0x02,
|
||||
.qam_demod_parameter_count = 2,
|
||||
.microcode_name = "dvb-usb-technisat-cablestar-hdci-drxk.fw",
|
||||
};
|
||||
|
||||
static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
|
||||
{
|
||||
struct az6007_device_state *st = fe_to_priv(fe);
|
||||
struct dvb_usb_adapter *adap = fe->sec_priv;
|
||||
int status = 0;
|
||||
|
||||
pr_debug("%s: %s\n", __func__, enable ? "enable" : "disable");
|
||||
|
||||
if (!adap || !st)
|
||||
return -EINVAL;
|
||||
|
||||
if (enable)
|
||||
status = st->gate_ctrl(fe, 1);
|
||||
else
|
||||
status = st->gate_ctrl(fe, 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct mt2063_config az6007_mt2063_config = {
|
||||
.tuner_address = 0x60,
|
||||
.refclock = 36125000,
|
||||
};
|
||||
|
||||
static int __az6007_read(struct usb_device *udev, u8 req, u16 value,
|
||||
u16 index, u8 *b, int blen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_control_msg(udev,
|
||||
usb_rcvctrlpipe(udev, 0),
|
||||
req,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
value, index, b, blen, 5000);
|
||||
if (ret < 0) {
|
||||
pr_warn("usb read operation failed. (%d)\n", ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (az6007_xfer_debug) {
|
||||
printk(KERN_DEBUG "az6007: IN req: %02x, value: %04x, index: %04x\n",
|
||||
req, value, index);
|
||||
print_hex_dump_bytes("az6007: payload: ",
|
||||
DUMP_PREFIX_NONE, b, blen);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_read(struct dvb_usb_device *d, u8 req, u16 value,
|
||||
u16 index, u8 *b, int blen)
|
||||
{
|
||||
struct az6007_device_state *st = d->priv;
|
||||
int ret;
|
||||
|
||||
if (mutex_lock_interruptible(&st->mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
ret = __az6007_read(d->udev, req, value, index, b, blen);
|
||||
|
||||
mutex_unlock(&st->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __az6007_write(struct usb_device *udev, u8 req, u16 value,
|
||||
u16 index, u8 *b, int blen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (az6007_xfer_debug) {
|
||||
printk(KERN_DEBUG "az6007: OUT req: %02x, value: %04x, index: %04x\n",
|
||||
req, value, index);
|
||||
print_hex_dump_bytes("az6007: payload: ",
|
||||
DUMP_PREFIX_NONE, b, blen);
|
||||
}
|
||||
|
||||
if (blen > 64) {
|
||||
pr_err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n",
|
||||
blen);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = usb_control_msg(udev,
|
||||
usb_sndctrlpipe(udev, 0),
|
||||
req,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
value, index, b, blen, 5000);
|
||||
if (ret != blen) {
|
||||
pr_err("usb write operation failed. (%d)\n", ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value,
|
||||
u16 index, u8 *b, int blen)
|
||||
{
|
||||
struct az6007_device_state *st = d->priv;
|
||||
int ret;
|
||||
|
||||
if (mutex_lock_interruptible(&st->mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
ret = __az6007_write(d->udev, req, value, index, b, blen);
|
||||
|
||||
mutex_unlock(&st->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_streaming_ctrl(struct dvb_frontend *fe, int onoff)
|
||||
{
|
||||
struct dvb_usb_device *d = fe_to_d(fe);
|
||||
|
||||
pr_debug("%s: %s\n", __func__, onoff ? "enable" : "disable");
|
||||
|
||||
return az6007_write(d, 0xbc, onoff, 0, NULL, 0);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_RC_CORE)
|
||||
/* remote control stuff (does not work with my box) */
|
||||
static int az6007_rc_query(struct dvb_usb_device *d)
|
||||
{
|
||||
struct az6007_device_state *st = d_to_priv(d);
|
||||
unsigned code;
|
||||
|
||||
az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10);
|
||||
|
||||
if (st->data[1] == 0x44)
|
||||
return 0;
|
||||
|
||||
if ((st->data[3] ^ st->data[4]) == 0xff) {
|
||||
if ((st->data[1] ^ st->data[2]) == 0xff)
|
||||
code = RC_SCANCODE_NEC(st->data[1], st->data[3]);
|
||||
else
|
||||
code = RC_SCANCODE_NECX(st->data[1] << 8 | st->data[2],
|
||||
st->data[3]);
|
||||
} else {
|
||||
code = RC_SCANCODE_NEC32(st->data[1] << 24 |
|
||||
st->data[2] << 16 |
|
||||
st->data[3] << 8 |
|
||||
st->data[4]);
|
||||
}
|
||||
|
||||
rc_keydown(d->rc_dev, RC_TYPE_NEC, code, st->data[5]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
|
||||
{
|
||||
pr_debug("Getting az6007 Remote Control properties\n");
|
||||
|
||||
rc->allowed_protos = RC_BIT_NEC;
|
||||
rc->query = az6007_rc_query;
|
||||
rc->interval = 400;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define az6007_get_rc_config NULL
|
||||
#endif
|
||||
|
||||
static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
|
||||
int slot,
|
||||
int address)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = d_to_priv(d);
|
||||
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value;
|
||||
u16 index;
|
||||
int blen;
|
||||
u8 *b;
|
||||
|
||||
if (slot != 0)
|
||||
return -EINVAL;
|
||||
|
||||
b = kmalloc(12, GFP_KERNEL);
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&state->ca_mutex);
|
||||
|
||||
req = 0xC1;
|
||||
value = address;
|
||||
index = 0;
|
||||
blen = 1;
|
||||
|
||||
ret = az6007_read(d, req, value, index, b, blen);
|
||||
if (ret < 0) {
|
||||
pr_warn("usb in operation failed. (%d)\n", ret);
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
ret = b[0];
|
||||
}
|
||||
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
kfree(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
|
||||
int slot,
|
||||
int address,
|
||||
u8 value)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = d_to_priv(d);
|
||||
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value1;
|
||||
u16 index;
|
||||
int blen;
|
||||
|
||||
pr_debug("%s(), slot %d\n", __func__, slot);
|
||||
if (slot != 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&state->ca_mutex);
|
||||
req = 0xC2;
|
||||
value1 = address;
|
||||
index = value;
|
||||
blen = 0;
|
||||
|
||||
ret = az6007_write(d, req, value1, index, NULL, blen);
|
||||
if (ret != 0)
|
||||
pr_warn("usb out operation failed. (%d)\n", ret);
|
||||
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca,
|
||||
int slot,
|
||||
u8 address)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = d_to_priv(d);
|
||||
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value;
|
||||
u16 index;
|
||||
int blen;
|
||||
u8 *b;
|
||||
|
||||
if (slot != 0)
|
||||
return -EINVAL;
|
||||
|
||||
b = kmalloc(12, GFP_KERNEL);
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&state->ca_mutex);
|
||||
|
||||
req = 0xC3;
|
||||
value = address;
|
||||
index = 0;
|
||||
blen = 2;
|
||||
|
||||
ret = az6007_read(d, req, value, index, b, blen);
|
||||
if (ret < 0) {
|
||||
pr_warn("usb in operation failed. (%d)\n", ret);
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
if (b[0] == 0)
|
||||
pr_warn("Read CI IO error\n");
|
||||
|
||||
ret = b[1];
|
||||
pr_debug("read cam data = %x from 0x%x\n", b[1], value);
|
||||
}
|
||||
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
kfree(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca,
|
||||
int slot,
|
||||
u8 address,
|
||||
u8 value)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = d_to_priv(d);
|
||||
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value1;
|
||||
u16 index;
|
||||
int blen;
|
||||
|
||||
if (slot != 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&state->ca_mutex);
|
||||
req = 0xC4;
|
||||
value1 = address;
|
||||
index = value;
|
||||
blen = 0;
|
||||
|
||||
ret = az6007_write(d, req, value1, index, NULL, blen);
|
||||
if (ret != 0) {
|
||||
pr_warn("usb out operation failed. (%d)\n", ret);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
failed:
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value;
|
||||
u16 index;
|
||||
int blen;
|
||||
u8 *b;
|
||||
|
||||
b = kmalloc(12, GFP_KERNEL);
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
req = 0xC8;
|
||||
value = 0;
|
||||
index = 0;
|
||||
blen = 1;
|
||||
|
||||
ret = az6007_read(d, req, value, index, b, blen);
|
||||
if (ret < 0) {
|
||||
pr_warn("usb in operation failed. (%d)\n", ret);
|
||||
ret = -EIO;
|
||||
} else{
|
||||
ret = b[0];
|
||||
}
|
||||
kfree(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = d_to_priv(d);
|
||||
|
||||
int ret, i;
|
||||
u8 req;
|
||||
u16 value;
|
||||
u16 index;
|
||||
int blen;
|
||||
|
||||
mutex_lock(&state->ca_mutex);
|
||||
|
||||
req = 0xC6;
|
||||
value = 1;
|
||||
index = 0;
|
||||
blen = 0;
|
||||
|
||||
ret = az6007_write(d, req, value, index, NULL, blen);
|
||||
if (ret != 0) {
|
||||
pr_warn("usb out operation failed. (%d)\n", ret);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
msleep(500);
|
||||
req = 0xC6;
|
||||
value = 0;
|
||||
index = 0;
|
||||
blen = 0;
|
||||
|
||||
ret = az6007_write(d, req, value, index, NULL, blen);
|
||||
if (ret != 0) {
|
||||
pr_warn("usb out operation failed. (%d)\n", ret);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
for (i = 0; i < 15; i++) {
|
||||
msleep(100);
|
||||
|
||||
if (CI_CamReady(ca, slot)) {
|
||||
pr_debug("CAM Ready\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
msleep(5000);
|
||||
|
||||
failed:
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = d_to_priv(d);
|
||||
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value;
|
||||
u16 index;
|
||||
int blen;
|
||||
|
||||
pr_debug("%s()\n", __func__);
|
||||
mutex_lock(&state->ca_mutex);
|
||||
req = 0xC7;
|
||||
value = 1;
|
||||
index = 0;
|
||||
blen = 0;
|
||||
|
||||
ret = az6007_write(d, req, value, index, NULL, blen);
|
||||
if (ret != 0) {
|
||||
pr_warn("usb out operation failed. (%d)\n", ret);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
failed:
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = d_to_priv(d);
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value;
|
||||
u16 index;
|
||||
int blen;
|
||||
u8 *b;
|
||||
|
||||
b = kmalloc(12, GFP_KERNEL);
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
mutex_lock(&state->ca_mutex);
|
||||
|
||||
req = 0xC5;
|
||||
value = 0;
|
||||
index = 0;
|
||||
blen = 1;
|
||||
|
||||
ret = az6007_read(d, req, value, index, b, blen);
|
||||
if (ret < 0) {
|
||||
pr_warn("usb in operation failed. (%d)\n", ret);
|
||||
ret = -EIO;
|
||||
} else
|
||||
ret = 0;
|
||||
|
||||
if (!ret && b[0] == 1) {
|
||||
ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
|
||||
DVB_CA_EN50221_POLL_CAM_READY;
|
||||
}
|
||||
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
kfree(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void az6007_ci_uninit(struct dvb_usb_device *d)
|
||||
{
|
||||
struct az6007_device_state *state;
|
||||
|
||||
pr_debug("%s()\n", __func__);
|
||||
|
||||
if (NULL == d)
|
||||
return;
|
||||
|
||||
state = d_to_priv(d);
|
||||
if (NULL == state)
|
||||
return;
|
||||
|
||||
if (NULL == state->ca.data)
|
||||
return;
|
||||
|
||||
dvb_ca_en50221_release(&state->ca);
|
||||
|
||||
memset(&state->ca, 0, sizeof(state->ca));
|
||||
}
|
||||
|
||||
|
||||
static int az6007_ci_init(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dvb_usb_device *d = adap_to_d(adap);
|
||||
struct az6007_device_state *state = adap_to_priv(adap);
|
||||
int ret;
|
||||
|
||||
pr_debug("%s()\n", __func__);
|
||||
|
||||
mutex_init(&state->ca_mutex);
|
||||
state->ca.owner = THIS_MODULE;
|
||||
state->ca.read_attribute_mem = az6007_ci_read_attribute_mem;
|
||||
state->ca.write_attribute_mem = az6007_ci_write_attribute_mem;
|
||||
state->ca.read_cam_control = az6007_ci_read_cam_control;
|
||||
state->ca.write_cam_control = az6007_ci_write_cam_control;
|
||||
state->ca.slot_reset = az6007_ci_slot_reset;
|
||||
state->ca.slot_shutdown = az6007_ci_slot_shutdown;
|
||||
state->ca.slot_ts_enable = az6007_ci_slot_ts_enable;
|
||||
state->ca.poll_slot_status = az6007_ci_poll_slot_status;
|
||||
state->ca.data = d;
|
||||
|
||||
ret = dvb_ca_en50221_init(&adap->dvb_adap,
|
||||
&state->ca,
|
||||
0, /* flags */
|
||||
1);/* n_slots */
|
||||
if (ret != 0) {
|
||||
pr_err("Cannot initialize CI: Error %d.\n", ret);
|
||||
memset(&state->ca, 0, sizeof(state->ca));
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_debug("CI initialized.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int az6007_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
|
||||
{
|
||||
struct dvb_usb_device *d = adap_to_d(adap);
|
||||
struct az6007_device_state *st = adap_to_priv(adap);
|
||||
int ret;
|
||||
|
||||
ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6);
|
||||
memcpy(mac, st->data, 6);
|
||||
|
||||
if (ret > 0)
|
||||
pr_debug("%s: mac is %pM\n", __func__, mac);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct az6007_device_state *st = adap_to_priv(adap);
|
||||
struct dvb_usb_device *d = adap_to_d(adap);
|
||||
|
||||
pr_debug("attaching demod drxk\n");
|
||||
|
||||
adap->fe[0] = dvb_attach(drxk_attach, &terratec_h7_drxk,
|
||||
&d->i2c_adap);
|
||||
if (!adap->fe[0])
|
||||
return -EINVAL;
|
||||
|
||||
adap->fe[0]->sec_priv = adap;
|
||||
st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl;
|
||||
adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
|
||||
|
||||
az6007_ci_init(adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int az6007_cablestar_hdci_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct az6007_device_state *st = adap_to_priv(adap);
|
||||
struct dvb_usb_device *d = adap_to_d(adap);
|
||||
|
||||
pr_debug("attaching demod drxk\n");
|
||||
|
||||
adap->fe[0] = dvb_attach(drxk_attach, &cablestar_hdci_drxk,
|
||||
&d->i2c_adap);
|
||||
if (!adap->fe[0])
|
||||
return -EINVAL;
|
||||
|
||||
adap->fe[0]->sec_priv = adap;
|
||||
st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl;
|
||||
adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
|
||||
|
||||
az6007_ci_init(adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int az6007_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dvb_usb_device *d = adap_to_d(adap);
|
||||
|
||||
pr_debug("attaching tuner mt2063\n");
|
||||
|
||||
/* Attach mt2063 to DVB-C frontend */
|
||||
if (adap->fe[0]->ops.i2c_gate_ctrl)
|
||||
adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 1);
|
||||
if (!dvb_attach(mt2063_attach, adap->fe[0],
|
||||
&az6007_mt2063_config,
|
||||
&d->i2c_adap))
|
||||
return -EINVAL;
|
||||
|
||||
if (adap->fe[0]->ops.i2c_gate_ctrl)
|
||||
adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
struct az6007_device_state *state = d_to_priv(d);
|
||||
int ret;
|
||||
|
||||
pr_debug("%s()\n", __func__);
|
||||
|
||||
if (!state->warm) {
|
||||
mutex_init(&state->mutex);
|
||||
|
||||
ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
msleep(60);
|
||||
ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
msleep(100);
|
||||
ret = az6007_write(d, AZ6007_POWER, 1, 3, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
msleep(20);
|
||||
ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
msleep(400);
|
||||
ret = az6007_write(d, FX2_SCON1, 0, 3, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
msleep(150);
|
||||
ret = az6007_write(d, FX2_SCON1, 1, 3, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
msleep(430);
|
||||
ret = az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
state->warm = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!onoff)
|
||||
return 0;
|
||||
|
||||
az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
|
||||
az6007_write(d, AZ6007_TS_THROUGH, 0, 0, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
struct az6007_device_state *st = d_to_priv(d);
|
||||
int i, j, len;
|
||||
int ret = 0;
|
||||
u16 index;
|
||||
u16 value;
|
||||
int length;
|
||||
u8 req, addr;
|
||||
|
||||
if (mutex_lock_interruptible(&st->mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
addr = msgs[i].addr << 1;
|
||||
if (((i + 1) < num)
|
||||
&& (msgs[i].len == 1)
|
||||
&& ((msgs[i].flags & I2C_M_RD) != I2C_M_RD)
|
||||
&& (msgs[i + 1].flags & I2C_M_RD)
|
||||
&& (msgs[i].addr == msgs[i + 1].addr)) {
|
||||
/*
|
||||
* A write + read xfer for the same address, where
|
||||
* the first xfer has just 1 byte length.
|
||||
* Need to join both into one operation
|
||||
*/
|
||||
if (az6007_xfer_debug)
|
||||
printk(KERN_DEBUG "az6007: I2C W/R addr=0x%x len=%d/%d\n",
|
||||
addr, msgs[i].len, msgs[i + 1].len);
|
||||
req = AZ6007_I2C_RD;
|
||||
index = msgs[i].buf[0];
|
||||
value = addr | (1 << 8);
|
||||
length = 6 + msgs[i + 1].len;
|
||||
len = msgs[i + 1].len;
|
||||
ret = __az6007_read(d->udev, req, value, index,
|
||||
st->data, length);
|
||||
if (ret >= len) {
|
||||
for (j = 0; j < len; j++)
|
||||
msgs[i + 1].buf[j] = st->data[j + 5];
|
||||
} else
|
||||
ret = -EIO;
|
||||
i++;
|
||||
} else if (!(msgs[i].flags & I2C_M_RD)) {
|
||||
/* write bytes */
|
||||
if (az6007_xfer_debug)
|
||||
printk(KERN_DEBUG "az6007: I2C W addr=0x%x len=%d\n",
|
||||
addr, msgs[i].len);
|
||||
req = AZ6007_I2C_WR;
|
||||
index = msgs[i].buf[0];
|
||||
value = addr | (1 << 8);
|
||||
length = msgs[i].len - 1;
|
||||
len = msgs[i].len - 1;
|
||||
for (j = 0; j < len; j++)
|
||||
st->data[j] = msgs[i].buf[j + 1];
|
||||
ret = __az6007_write(d->udev, req, value, index,
|
||||
st->data, length);
|
||||
} else {
|
||||
/* read bytes */
|
||||
if (az6007_xfer_debug)
|
||||
printk(KERN_DEBUG "az6007: I2C R addr=0x%x len=%d\n",
|
||||
addr, msgs[i].len);
|
||||
req = AZ6007_I2C_RD;
|
||||
index = msgs[i].buf[0];
|
||||
value = addr;
|
||||
length = msgs[i].len + 6;
|
||||
len = msgs[i].len;
|
||||
ret = __az6007_read(d->udev, req, value, index,
|
||||
st->data, length);
|
||||
for (j = 0; j < len; j++)
|
||||
msgs[i].buf[j] = st->data[j + 5];
|
||||
}
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
err:
|
||||
mutex_unlock(&st->mutex);
|
||||
|
||||
if (ret < 0) {
|
||||
pr_info("%s ERROR: %i\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
static u32 az6007_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm az6007_i2c_algo = {
|
||||
.master_xfer = az6007_i2c_xfer,
|
||||
.functionality = az6007_i2c_func,
|
||||
};
|
||||
|
||||
static int az6007_identify_state(struct dvb_usb_device *d, const char **name)
|
||||
{
|
||||
int ret;
|
||||
u8 *mac;
|
||||
|
||||
pr_debug("Identifying az6007 state\n");
|
||||
|
||||
mac = kmalloc(6, GFP_ATOMIC);
|
||||
if (!mac)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Try to read the mac address */
|
||||
ret = __az6007_read(d->udev, AZ6007_READ_DATA, 6, 0, mac, 6);
|
||||
if (ret == 6)
|
||||
ret = WARM;
|
||||
else
|
||||
ret = COLD;
|
||||
|
||||
kfree(mac);
|
||||
|
||||
if (ret == COLD) {
|
||||
__az6007_write(d->udev, 0x09, 1, 0, NULL, 0);
|
||||
__az6007_write(d->udev, 0x00, 0, 0, NULL, 0);
|
||||
__az6007_write(d->udev, 0x00, 0, 0, NULL, 0);
|
||||
}
|
||||
|
||||
pr_debug("Device is on %s state\n",
|
||||
ret == WARM ? "warm" : "cold");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void az6007_usb_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct dvb_usb_device *d = usb_get_intfdata(intf);
|
||||
az6007_ci_uninit(d);
|
||||
dvb_usbv2_disconnect(intf);
|
||||
}
|
||||
|
||||
static int az6007_download_firmware(struct dvb_usb_device *d,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
pr_debug("Loading az6007 firmware\n");
|
||||
|
||||
return cypress_load_firmware(d->udev, fw, CYPRESS_FX2);
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties az6007_props = {
|
||||
.driver_name = KBUILD_MODNAME,
|
||||
.owner = THIS_MODULE,
|
||||
.firmware = AZ6007_FIRMWARE,
|
||||
|
||||
.adapter_nr = adapter_nr,
|
||||
.size_of_priv = sizeof(struct az6007_device_state),
|
||||
.i2c_algo = &az6007_i2c_algo,
|
||||
.tuner_attach = az6007_tuner_attach,
|
||||
.frontend_attach = az6007_frontend_attach,
|
||||
.streaming_ctrl = az6007_streaming_ctrl,
|
||||
.get_rc_config = az6007_get_rc_config,
|
||||
.read_mac_address = az6007_read_mac_addr,
|
||||
.download_firmware = az6007_download_firmware,
|
||||
.identify_state = az6007_identify_state,
|
||||
.power_ctrl = az6007_power_ctrl,
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{ .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), }
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties az6007_cablestar_hdci_props = {
|
||||
.driver_name = KBUILD_MODNAME,
|
||||
.owner = THIS_MODULE,
|
||||
.firmware = AZ6007_FIRMWARE,
|
||||
|
||||
.adapter_nr = adapter_nr,
|
||||
.size_of_priv = sizeof(struct az6007_device_state),
|
||||
.i2c_algo = &az6007_i2c_algo,
|
||||
.tuner_attach = az6007_tuner_attach,
|
||||
.frontend_attach = az6007_cablestar_hdci_frontend_attach,
|
||||
.streaming_ctrl = az6007_streaming_ctrl,
|
||||
/* ditch get_rc_config as it can't work (TS35 remote, I believe it's rc5) */
|
||||
.get_rc_config = NULL,
|
||||
.read_mac_address = az6007_read_mac_addr,
|
||||
.download_firmware = az6007_download_firmware,
|
||||
.identify_state = az6007_identify_state,
|
||||
.power_ctrl = az6007_power_ctrl,
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{ .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), }
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_device_id az6007_usb_table[] = {
|
||||
{DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007,
|
||||
&az6007_props, "Azurewave 6007", RC_MAP_EMPTY)},
|
||||
{DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7,
|
||||
&az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
|
||||
{DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2,
|
||||
&az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
|
||||
{DVB_USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI,
|
||||
&az6007_cablestar_hdci_props, "Technisat CableStar Combo HD CI", RC_MAP_EMPTY)},
|
||||
{0},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, az6007_usb_table);
|
||||
|
||||
static int az6007_suspend(struct usb_interface *intf, pm_message_t msg)
|
||||
{
|
||||
struct dvb_usb_device *d = usb_get_intfdata(intf);
|
||||
|
||||
az6007_ci_uninit(d);
|
||||
return dvb_usbv2_suspend(intf, msg);
|
||||
}
|
||||
|
||||
static int az6007_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct dvb_usb_device *d = usb_get_intfdata(intf);
|
||||
struct dvb_usb_adapter *adap = &d->adapter[0];
|
||||
|
||||
az6007_ci_init(adap);
|
||||
return dvb_usbv2_resume(intf);
|
||||
}
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver az6007_usb_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = az6007_usb_table,
|
||||
.probe = dvb_usbv2_probe,
|
||||
.disconnect = az6007_usb_disconnect,
|
||||
.no_dynamic_id = 1,
|
||||
.soft_unbind = 1,
|
||||
/*
|
||||
* FIXME: need to implement reset_resume, likely with
|
||||
* dvb-usb-v2 core support
|
||||
*/
|
||||
.suspend = az6007_suspend,
|
||||
.resume = az6007_resume,
|
||||
};
|
||||
|
||||
module_usb_driver(az6007_usb_driver);
|
||||
|
||||
MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
|
||||
MODULE_AUTHOR("Mauro Carvalho Chehab");
|
||||
MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
|
||||
MODULE_VERSION("2.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_FIRMWARE(AZ6007_FIRMWARE);
|
||||
292
drivers/media/usb/dvb-usb-v2/ce6230.c
Normal file
292
drivers/media/usb/dvb-usb-v2/ce6230.c
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* Intel CE6230 DVB USB driver
|
||||
*
|
||||
* Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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 "ce6230.h"
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
|
||||
{
|
||||
int ret;
|
||||
unsigned int pipe;
|
||||
u8 request;
|
||||
u8 requesttype;
|
||||
u16 value;
|
||||
u16 index;
|
||||
u8 *buf;
|
||||
|
||||
request = req->cmd;
|
||||
value = req->value;
|
||||
index = req->index;
|
||||
|
||||
switch (req->cmd) {
|
||||
case I2C_READ:
|
||||
case DEMOD_READ:
|
||||
case REG_READ:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
|
||||
break;
|
||||
case I2C_WRITE:
|
||||
case DEMOD_WRITE:
|
||||
case REG_WRITE:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
|
||||
break;
|
||||
default:
|
||||
dev_err(&d->udev->dev, "%s: unknown command=%02x\n",
|
||||
KBUILD_MODNAME, req->cmd);
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
buf = kmalloc(req->data_len, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
|
||||
/* write */
|
||||
memcpy(buf, req->data, req->data_len);
|
||||
pipe = usb_sndctrlpipe(d->udev, 0);
|
||||
} else {
|
||||
/* read */
|
||||
pipe = usb_rcvctrlpipe(d->udev, 0);
|
||||
}
|
||||
|
||||
msleep(1); /* avoid I2C errors */
|
||||
|
||||
ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index,
|
||||
buf, req->data_len, CE6230_USB_TIMEOUT);
|
||||
|
||||
dvb_usb_dbg_usb_control_msg(d->udev, request, requesttype, value, index,
|
||||
buf, req->data_len);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&d->udev->dev, "%s: usb_control_msg() failed=%d\n",
|
||||
KBUILD_MODNAME, ret);
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
/* read request, copy returned data to return buf */
|
||||
if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
|
||||
memcpy(req->data, buf, req->data_len);
|
||||
|
||||
kfree(buf);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static struct zl10353_config ce6230_zl10353_config;
|
||||
|
||||
static int ce6230_i2c_master_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;
|
||||
struct usb_req req;
|
||||
|
||||
if (num > 2)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
while (i < num) {
|
||||
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (msg[i].addr ==
|
||||
ce6230_zl10353_config.demod_address) {
|
||||
req.cmd = DEMOD_READ;
|
||||
req.value = msg[i].addr >> 1;
|
||||
req.index = msg[i].buf[0];
|
||||
req.data_len = msg[i+1].len;
|
||||
req.data = &msg[i+1].buf[0];
|
||||
ret = ce6230_ctrl_msg(d, &req);
|
||||
} else {
|
||||
dev_err(&d->udev->dev, "%s: I2C read not " \
|
||||
"implemented\n",
|
||||
KBUILD_MODNAME);
|
||||
ret = -EOPNOTSUPP;
|
||||
}
|
||||
i += 2;
|
||||
} else {
|
||||
if (msg[i].addr ==
|
||||
ce6230_zl10353_config.demod_address) {
|
||||
req.cmd = DEMOD_WRITE;
|
||||
req.value = msg[i].addr >> 1;
|
||||
req.index = msg[i].buf[0];
|
||||
req.data_len = msg[i].len-1;
|
||||
req.data = &msg[i].buf[1];
|
||||
ret = ce6230_ctrl_msg(d, &req);
|
||||
} else {
|
||||
req.cmd = I2C_WRITE;
|
||||
req.value = 0x2000 + (msg[i].addr >> 1);
|
||||
req.index = 0x0000;
|
||||
req.data_len = msg[i].len;
|
||||
req.data = &msg[i].buf[0];
|
||||
ret = ce6230_ctrl_msg(d, &req);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return ret ? ret : i;
|
||||
}
|
||||
|
||||
static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm ce6230_i2c_algorithm = {
|
||||
.master_xfer = ce6230_i2c_master_xfer,
|
||||
.functionality = ce6230_i2c_functionality,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static struct zl10353_config ce6230_zl10353_config = {
|
||||
.demod_address = 0x1e,
|
||||
.adc_clock = 450000,
|
||||
.if2 = 45700,
|
||||
.no_tuner = 1,
|
||||
.parallel_ts = 1,
|
||||
.clock_ctl_1 = 0x34,
|
||||
.pll_0 = 0x0e,
|
||||
};
|
||||
|
||||
static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dvb_usb_device *d = adap_to_d(adap);
|
||||
|
||||
dev_dbg(&d->udev->dev, "%s:\n", __func__);
|
||||
|
||||
adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
|
||||
&d->i2c_adap);
|
||||
if (adap->fe[0] == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mxl5005s_config ce6230_mxl5003s_config = {
|
||||
.i2c_address = 0xc6,
|
||||
.if_freq = IF_FREQ_4570000HZ,
|
||||
.xtal_freq = CRYSTAL_FREQ_16000000HZ,
|
||||
.agc_mode = MXL_SINGLE_AGC,
|
||||
.tracking_filter = MXL_TF_DEFAULT,
|
||||
.rssi_enable = MXL_RSSI_ENABLE,
|
||||
.cap_select = MXL_CAP_SEL_ENABLE,
|
||||
.div_out = MXL_DIV_OUT_4,
|
||||
.clock_out = MXL_CLOCK_OUT_DISABLE,
|
||||
.output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
|
||||
.top = MXL5005S_TOP_25P2,
|
||||
.mod_mode = MXL_DIGITAL_MODE,
|
||||
.if_mode = MXL_ZERO_IF,
|
||||
.AgcMasterByte = 0x00,
|
||||
};
|
||||
|
||||
static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dvb_usb_device *d = adap_to_d(adap);
|
||||
int ret;
|
||||
|
||||
dev_dbg(&d->udev->dev, "%s:\n", __func__);
|
||||
|
||||
ret = dvb_attach(mxl5005s_attach, adap->fe[0], &d->i2c_adap,
|
||||
&ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
int ret;
|
||||
|
||||
dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
|
||||
|
||||
/* InterfaceNumber 1 / AlternateSetting 0 idle
|
||||
InterfaceNumber 1 / AlternateSetting 1 streaming */
|
||||
ret = usb_set_interface(d->udev, 1, onoff);
|
||||
if (ret)
|
||||
dev_err(&d->udev->dev, "%s: usb_set_interface() failed=%d\n",
|
||||
KBUILD_MODNAME, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties ce6230_props = {
|
||||
.driver_name = KBUILD_MODNAME,
|
||||
.owner = THIS_MODULE,
|
||||
.adapter_nr = adapter_nr,
|
||||
.bInterfaceNumber = 1,
|
||||
|
||||
.i2c_algo = &ce6230_i2c_algorithm,
|
||||
.power_ctrl = ce6230_power_ctrl,
|
||||
.frontend_attach = ce6230_zl10353_frontend_attach,
|
||||
.tuner_attach = ce6230_mxl5003s_tuner_attach,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 6,
|
||||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = (16 * 512),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
static const struct usb_device_id ce6230_id_table[] = {
|
||||
{ DVB_USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500,
|
||||
&ce6230_props, "Intel CE9500 reference design", NULL) },
|
||||
{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310,
|
||||
&ce6230_props, "AVerMedia A310 USB 2.0 DVB-T tuner", NULL) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, ce6230_id_table);
|
||||
|
||||
static struct usb_driver ce6230_usb_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = ce6230_id_table,
|
||||
.probe = dvb_usbv2_probe,
|
||||
.disconnect = dvb_usbv2_disconnect,
|
||||
.suspend = dvb_usbv2_suspend,
|
||||
.resume = dvb_usbv2_resume,
|
||||
.reset_resume = dvb_usbv2_reset_resume,
|
||||
.no_dynamic_id = 1,
|
||||
.soft_unbind = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(ce6230_usb_driver);
|
||||
|
||||
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
|
||||
MODULE_DESCRIPTION("Intel CE6230 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
50
drivers/media/usb/dvb-usb-v2/ce6230.h
Normal file
50
drivers/media/usb/dvb-usb-v2/ce6230.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Intel CE6230 DVB USB driver
|
||||
*
|
||||
* Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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 CE6230_H
|
||||
#define CE6230_H
|
||||
|
||||
#include "dvb_usb.h"
|
||||
#include "zl10353.h"
|
||||
#include "mxl5005s.h"
|
||||
|
||||
#define CE6230_USB_TIMEOUT 1000
|
||||
|
||||
struct usb_req {
|
||||
u8 cmd; /* [1] */
|
||||
u16 value; /* [2|3] */
|
||||
u16 index; /* [4|5] */
|
||||
u16 data_len; /* [6|7] */
|
||||
u8 *data;
|
||||
};
|
||||
|
||||
enum ce6230_cmd {
|
||||
CONFIG_READ = 0xd0, /* rd 0 (unclear) */
|
||||
UNKNOWN_WRITE = 0xc7, /* wr 7 (unclear) */
|
||||
I2C_READ = 0xd9, /* rd 9 (unclear) */
|
||||
I2C_WRITE = 0xca, /* wr a */
|
||||
DEMOD_READ = 0xdb, /* rd b */
|
||||
DEMOD_WRITE = 0xcc, /* wr c */
|
||||
REG_READ = 0xde, /* rd e */
|
||||
REG_WRITE = 0xcf, /* wr f */
|
||||
};
|
||||
|
||||
#endif
|
||||
409
drivers/media/usb/dvb-usb-v2/dvb_usb.h
Normal file
409
drivers/media/usb/dvb-usb-v2/dvb_usb.h
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
/*
|
||||
* DVB USB framework
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
|
||||
* Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef DVB_USB_H
|
||||
#define DVB_USB_H
|
||||
|
||||
#include <linux/usb/input.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <media/rc-core.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_net.h"
|
||||
#include "dmxdev.h"
|
||||
#include "dvb-usb-ids.h"
|
||||
|
||||
/*
|
||||
* device file: /dev/dvb/adapter[0-1]/frontend[0-2]
|
||||
*
|
||||
* |-- device
|
||||
* | |-- adapter0
|
||||
* | | |-- frontend0
|
||||
* | | |-- frontend1
|
||||
* | | `-- frontend2
|
||||
* | `-- adapter1
|
||||
* | |-- frontend0
|
||||
* | |-- frontend1
|
||||
* | `-- frontend2
|
||||
*
|
||||
*
|
||||
* Commonly used variable names:
|
||||
* d = pointer to device (struct dvb_usb_device *)
|
||||
* adap = pointer to adapter (struct dvb_usb_adapter *)
|
||||
* fe = pointer to frontend (struct dvb_frontend *)
|
||||
*
|
||||
* Use macros defined in that file to resolve needed pointers.
|
||||
*/
|
||||
|
||||
/* helper macros for every DVB USB driver use */
|
||||
#define adap_to_d(adap) (container_of(adap, struct dvb_usb_device, \
|
||||
adapter[adap->id]))
|
||||
#define adap_to_priv(adap) (adap_to_d(adap)->priv)
|
||||
#define fe_to_adap(fe) ((struct dvb_usb_adapter *) ((fe)->dvb->priv))
|
||||
#define fe_to_d(fe) (adap_to_d(fe_to_adap(fe)))
|
||||
#define fe_to_priv(fe) (fe_to_d(fe)->priv)
|
||||
#define d_to_priv(d) (d->priv)
|
||||
|
||||
#define dvb_usb_dbg_usb_control_msg(udev, r, t, v, i, b, l) { \
|
||||
char *direction; \
|
||||
if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
|
||||
direction = ">>>"; \
|
||||
else \
|
||||
direction = "<<<"; \
|
||||
dev_dbg(&udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \
|
||||
"%s %*ph\n", __func__, t, r, v & 0xff, v >> 8, \
|
||||
i & 0xff, i >> 8, l & 0xff, l >> 8, direction, l, b); \
|
||||
}
|
||||
|
||||
#define DVB_USB_STREAM_BULK(endpoint_, count_, size_) { \
|
||||
.type = USB_BULK, \
|
||||
.count = count_, \
|
||||
.endpoint = endpoint_, \
|
||||
.u = { \
|
||||
.bulk = { \
|
||||
.buffersize = size_, \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DVB_USB_STREAM_ISOC(endpoint_, count_, frames_, size_, interval_) { \
|
||||
.type = USB_ISOC, \
|
||||
.count = count_, \
|
||||
.endpoint = endpoint_, \
|
||||
.u = { \
|
||||
.isoc = { \
|
||||
.framesperurb = frames_, \
|
||||
.framesize = size_,\
|
||||
.interval = interval_, \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DVB_USB_DEVICE(vend, prod, props_, name_, rc) \
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
|
||||
.idVendor = (vend), \
|
||||
.idProduct = (prod), \
|
||||
.driver_info = (kernel_ulong_t) &((const struct dvb_usb_driver_info) { \
|
||||
.props = (props_), \
|
||||
.name = (name_), \
|
||||
.rc_map = (rc), \
|
||||
})
|
||||
|
||||
struct dvb_usb_device;
|
||||
struct dvb_usb_adapter;
|
||||
|
||||
/**
|
||||
* structure for carrying all needed data from the device driver to the general
|
||||
* dvb usb routines
|
||||
* @name: device name
|
||||
* @rc_map: name of rc codes table
|
||||
* @props: structure containing all device properties
|
||||
*/
|
||||
struct dvb_usb_driver_info {
|
||||
const char *name;
|
||||
const char *rc_map;
|
||||
const struct dvb_usb_device_properties *props;
|
||||
};
|
||||
|
||||
/**
|
||||
* structure for remote controller configuration
|
||||
* @map_name: name of rc codes table
|
||||
* @allowed_protos: protocol(s) supported by the driver
|
||||
* @change_protocol: callback to change protocol
|
||||
* @query: called to query an event from the device
|
||||
* @interval: time in ms between two queries
|
||||
* @driver_type: used to point if a device supports raw mode
|
||||
* @bulk_mode: device supports bulk mode for rc (disable polling mode)
|
||||
*/
|
||||
struct dvb_usb_rc {
|
||||
const char *map_name;
|
||||
u64 allowed_protos;
|
||||
int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
|
||||
int (*query) (struct dvb_usb_device *d);
|
||||
unsigned int interval;
|
||||
enum rc_driver_type driver_type;
|
||||
bool bulk_mode;
|
||||
};
|
||||
|
||||
/**
|
||||
* usb streaming configration for adapter
|
||||
* @type: urb type
|
||||
* @count: count of used urbs
|
||||
* @endpoint: stream usb endpoint number
|
||||
*/
|
||||
struct usb_data_stream_properties {
|
||||
#define USB_BULK 1
|
||||
#define USB_ISOC 2
|
||||
u8 type;
|
||||
u8 count;
|
||||
u8 endpoint;
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned int buffersize; /* per URB */
|
||||
} bulk;
|
||||
struct {
|
||||
int framesperurb;
|
||||
int framesize;
|
||||
int interval;
|
||||
} isoc;
|
||||
} u;
|
||||
};
|
||||
|
||||
/**
|
||||
* properties of dvb usb device adapter
|
||||
* @caps: adapter capabilities
|
||||
* @pid_filter_count: pid count of adapter pid-filter
|
||||
* @pid_filter_ctrl: called to enable/disable pid-filter
|
||||
* @pid_filter: called to set/unset pid for filtering
|
||||
* @stream: adapter usb stream configuration
|
||||
*/
|
||||
#define MAX_NO_OF_FE_PER_ADAP 3
|
||||
struct dvb_usb_adapter_properties {
|
||||
#define DVB_USB_ADAP_HAS_PID_FILTER 0x01
|
||||
#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
|
||||
#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04
|
||||
u8 caps;
|
||||
|
||||
u8 pid_filter_count;
|
||||
int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
|
||||
int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int);
|
||||
|
||||
struct usb_data_stream_properties stream;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvb_usb_device_properties - properties of a dvb-usb-device
|
||||
* @driver_name: name of the owning driver module
|
||||
* @owner: owner of the dvb_adapter
|
||||
* @adapter_nr: values from the DVB_DEFINE_MOD_OPT_ADAPTER_NR() macro
|
||||
* @bInterfaceNumber: usb interface number driver binds
|
||||
* @size_of_priv: bytes allocated for the driver private data
|
||||
* @generic_bulk_ctrl_endpoint: bulk control endpoint number for sent
|
||||
* @generic_bulk_ctrl_endpoint_response: bulk control endpoint number for
|
||||
* receive
|
||||
* @generic_bulk_ctrl_delay: delay between bulk control sent and receive message
|
||||
* @identify_state: called to determine the firmware state (cold or warm) and
|
||||
* return possible firmware file name to be loaded
|
||||
* @firmware: name of the firmware file to be loaded
|
||||
* @download_firmware: called to download the firmware
|
||||
* @i2c_algo: i2c_algorithm if the device has i2c-adapter
|
||||
* @num_adapters: dvb usb device adapter count
|
||||
* @get_adapter_count: called to resolve adapter count
|
||||
* @adapter: array of all adapter properties of device
|
||||
* @power_ctrl: called to enable/disable power of the device
|
||||
* @read_config: called to resolve device configuration
|
||||
* @read_mac_address: called to resolve adapter mac-address
|
||||
* @frontend_attach: called to attach the possible frontends
|
||||
* @frontend_detach: called to detach the possible frontends
|
||||
* @tuner_attach: called to attach the possible tuners
|
||||
* @frontend_ctrl: called to power on/off active frontend
|
||||
* @streaming_ctrl: called to start/stop the usb streaming of adapter
|
||||
* @init: called after adapters are created in order to finalize device
|
||||
* configuration
|
||||
* @exit: called when driver is unloaded
|
||||
* @get_rc_config: called to resolve used remote controller configuration
|
||||
* @get_stream_config: called to resolve input and output stream configuration
|
||||
* of the adapter just before streaming is started. input stream is transport
|
||||
* stream from the demodulator and output stream is usb stream to host.
|
||||
*/
|
||||
#define MAX_NO_OF_ADAPTER_PER_DEVICE 2
|
||||
struct dvb_usb_device_properties {
|
||||
const char *driver_name;
|
||||
struct module *owner;
|
||||
short *adapter_nr;
|
||||
|
||||
u8 bInterfaceNumber;
|
||||
unsigned int size_of_priv;
|
||||
u8 generic_bulk_ctrl_endpoint;
|
||||
u8 generic_bulk_ctrl_endpoint_response;
|
||||
unsigned int generic_bulk_ctrl_delay;
|
||||
|
||||
#define WARM 0
|
||||
#define COLD 1
|
||||
int (*identify_state) (struct dvb_usb_device *, const char **);
|
||||
const char *firmware;
|
||||
#define RECONNECTS_USB 1
|
||||
int (*download_firmware) (struct dvb_usb_device *,
|
||||
const struct firmware *);
|
||||
|
||||
struct i2c_algorithm *i2c_algo;
|
||||
|
||||
unsigned int num_adapters;
|
||||
int (*get_adapter_count) (struct dvb_usb_device *);
|
||||
struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
|
||||
int (*power_ctrl) (struct dvb_usb_device *, int);
|
||||
int (*read_config) (struct dvb_usb_device *d);
|
||||
int (*read_mac_address) (struct dvb_usb_adapter *, u8 []);
|
||||
int (*frontend_attach) (struct dvb_usb_adapter *);
|
||||
int (*frontend_detach)(struct dvb_usb_adapter *);
|
||||
int (*tuner_attach) (struct dvb_usb_adapter *);
|
||||
int (*tuner_detach)(struct dvb_usb_adapter *);
|
||||
int (*frontend_ctrl) (struct dvb_frontend *, int);
|
||||
int (*streaming_ctrl) (struct dvb_frontend *, int);
|
||||
int (*init) (struct dvb_usb_device *);
|
||||
void (*exit) (struct dvb_usb_device *);
|
||||
int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *);
|
||||
#define DVB_USB_FE_TS_TYPE_188 0
|
||||
#define DVB_USB_FE_TS_TYPE_204 1
|
||||
#define DVB_USB_FE_TS_TYPE_RAW 2
|
||||
int (*get_stream_config) (struct dvb_frontend *, u8 *,
|
||||
struct usb_data_stream_properties *);
|
||||
};
|
||||
|
||||
/**
|
||||
* generic object of an usb stream
|
||||
* @buf_num: number of buffer allocated
|
||||
* @buf_size: size of each buffer in buf_list
|
||||
* @buf_list: array containing all allocate buffers for streaming
|
||||
* @dma_addr: list of dma_addr_t for each buffer in buf_list
|
||||
*
|
||||
* @urbs_initialized: number of URBs initialized
|
||||
* @urbs_submitted: number of URBs submitted
|
||||
*/
|
||||
#define MAX_NO_URBS_FOR_DATA_STREAM 10
|
||||
struct usb_data_stream {
|
||||
struct usb_device *udev;
|
||||
struct usb_data_stream_properties props;
|
||||
|
||||
#define USB_STATE_INIT 0x00
|
||||
#define USB_STATE_URB_BUF 0x01
|
||||
u8 state;
|
||||
|
||||
void (*complete) (struct usb_data_stream *, u8 *, size_t);
|
||||
|
||||
struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM];
|
||||
int buf_num;
|
||||
unsigned long buf_size;
|
||||
u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM];
|
||||
dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM];
|
||||
|
||||
int urbs_initialized;
|
||||
int urbs_submitted;
|
||||
|
||||
void *user_priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* dvb adapter object on dvb usb device
|
||||
* @props: pointer to adapter properties
|
||||
* @stream: adapter the usb data stream
|
||||
* @id: index of this adapter (starting with 0)
|
||||
* @ts_type: transport stream, input stream, type
|
||||
* @suspend_resume_active: set when there is ongoing suspend / resume
|
||||
* @pid_filtering: is hardware pid_filtering used or not
|
||||
* @feed_count: current feed count
|
||||
* @max_feed_count: maimum feed count device can handle
|
||||
* @dvb_adap: adapter dvb_adapter
|
||||
* @dmxdev: adapter dmxdev
|
||||
* @demux: adapter software demuxer
|
||||
* @dvb_net: adapter dvb_net interfaces
|
||||
* @sync_mutex: mutex used to sync control and streaming of the adapter
|
||||
* @fe: adapter frontends
|
||||
* @fe_init: rerouted frontend-init function
|
||||
* @fe_sleep: rerouted frontend-sleep function
|
||||
*/
|
||||
struct dvb_usb_adapter {
|
||||
const struct dvb_usb_adapter_properties *props;
|
||||
struct usb_data_stream stream;
|
||||
u8 id;
|
||||
u8 ts_type;
|
||||
bool suspend_resume_active;
|
||||
bool pid_filtering;
|
||||
u8 feed_count;
|
||||
u8 max_feed_count;
|
||||
s8 active_fe;
|
||||
#define ADAP_INIT 0
|
||||
#define ADAP_SLEEP 1
|
||||
#define ADAP_STREAMING 2
|
||||
unsigned long state_bits;
|
||||
|
||||
/* dvb */
|
||||
struct dvb_adapter dvb_adap;
|
||||
struct dmxdev dmxdev;
|
||||
struct dvb_demux demux;
|
||||
struct dvb_net dvb_net;
|
||||
|
||||
struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP];
|
||||
int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *);
|
||||
int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *);
|
||||
};
|
||||
|
||||
/**
|
||||
* dvb usb device object
|
||||
* @props: device properties
|
||||
* @name: device name
|
||||
* @rc_map: name of rc codes table
|
||||
* @rc_polling_active: set when RC polling is active
|
||||
* @udev: pointer to the device's struct usb_device
|
||||
* @rc: remote controller configuration
|
||||
* @powered: indicated whether the device is power or not
|
||||
* @usb_mutex: mutex for usb control messages
|
||||
* @i2c_mutex: mutex for i2c-transfers
|
||||
* @i2c_adap: device's i2c-adapter
|
||||
* @rc_dev: rc device for the remote control
|
||||
* @rc_query_work: work for polling remote
|
||||
* @priv: private data of the actual driver (allocate by dvb usb, size defined
|
||||
* in size_of_priv of dvb_usb_properties).
|
||||
*/
|
||||
struct dvb_usb_device {
|
||||
const struct dvb_usb_device_properties *props;
|
||||
const char *name;
|
||||
const char *rc_map;
|
||||
bool rc_polling_active;
|
||||
struct usb_device *udev;
|
||||
struct dvb_usb_rc rc;
|
||||
int powered;
|
||||
|
||||
/* locking */
|
||||
struct mutex usb_mutex;
|
||||
|
||||
/* i2c */
|
||||
struct mutex i2c_mutex;
|
||||
struct i2c_adapter i2c_adap;
|
||||
|
||||
struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
|
||||
|
||||
/* remote control */
|
||||
struct rc_dev *rc_dev;
|
||||
char rc_phys[64];
|
||||
struct delayed_work rc_query_work;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
extern int dvb_usbv2_probe(struct usb_interface *,
|
||||
const struct usb_device_id *);
|
||||
extern void dvb_usbv2_disconnect(struct usb_interface *);
|
||||
extern int dvb_usbv2_suspend(struct usb_interface *, pm_message_t);
|
||||
extern int dvb_usbv2_resume(struct usb_interface *);
|
||||
extern int dvb_usbv2_reset_resume(struct usb_interface *);
|
||||
|
||||
/* the generic read/write method for device control */
|
||||
extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16);
|
||||
extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16);
|
||||
/* caller must hold lock when locked versions are called */
|
||||
extern int dvb_usbv2_generic_rw_locked(struct dvb_usb_device *,
|
||||
u8 *, u16, u8 *, u16);
|
||||
extern int dvb_usbv2_generic_write_locked(struct dvb_usb_device *, u8 *, u16);
|
||||
|
||||
#endif
|
||||
35
drivers/media/usb/dvb-usb-v2/dvb_usb_common.h
Normal file
35
drivers/media/usb/dvb-usb-v2/dvb_usb_common.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* DVB USB framework
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
|
||||
* Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef DVB_USB_COMMON_H
|
||||
#define DVB_USB_COMMON_H
|
||||
|
||||
#include "dvb_usb.h"
|
||||
|
||||
/* commonly used methods */
|
||||
extern int usb_urb_initv2(struct usb_data_stream *stream,
|
||||
const struct usb_data_stream_properties *props);
|
||||
extern int usb_urb_exitv2(struct usb_data_stream *stream);
|
||||
extern int usb_urb_submitv2(struct usb_data_stream *stream,
|
||||
struct usb_data_stream_properties *props);
|
||||
extern int usb_urb_killv2(struct usb_data_stream *stream);
|
||||
|
||||
#endif
|
||||
1064
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
Normal file
1064
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
Normal file
File diff suppressed because it is too large
Load diff
104
drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
Normal file
104
drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* DVB USB framework
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
|
||||
* Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "dvb_usb_common.h"
|
||||
|
||||
static int dvb_usb_v2_generic_io(struct dvb_usb_device *d,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
int ret, actual_length;
|
||||
|
||||
if (!wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint ||
|
||||
!d->props->generic_bulk_ctrl_endpoint_response) {
|
||||
dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, -EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, wlen, wbuf);
|
||||
|
||||
ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
|
||||
d->props->generic_bulk_ctrl_endpoint), wbuf, wlen,
|
||||
&actual_length, 2000);
|
||||
if (ret < 0)
|
||||
dev_err(&d->udev->dev, "%s: usb_bulk_msg() failed=%d\n",
|
||||
KBUILD_MODNAME, ret);
|
||||
else
|
||||
ret = actual_length != wlen ? -EIO : 0;
|
||||
|
||||
/* an answer is expected, and no error before */
|
||||
if (!ret && rbuf && rlen) {
|
||||
if (d->props->generic_bulk_ctrl_delay)
|
||||
usleep_range(d->props->generic_bulk_ctrl_delay,
|
||||
d->props->generic_bulk_ctrl_delay
|
||||
+ 20000);
|
||||
|
||||
ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
|
||||
d->props->generic_bulk_ctrl_endpoint_response),
|
||||
rbuf, rlen, &actual_length, 2000);
|
||||
if (ret)
|
||||
dev_err(&d->udev->dev,
|
||||
"%s: 2nd usb_bulk_msg() failed=%d\n",
|
||||
KBUILD_MODNAME, ret);
|
||||
|
||||
dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__,
|
||||
actual_length, rbuf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dvb_usbv2_generic_rw(struct dvb_usb_device *d,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&d->usb_mutex);
|
||||
ret = dvb_usb_v2_generic_io(d, wbuf, wlen, rbuf, rlen);
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usbv2_generic_rw);
|
||||
|
||||
int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&d->usb_mutex);
|
||||
ret = dvb_usb_v2_generic_io(d, buf, len, NULL, 0);
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usbv2_generic_write);
|
||||
|
||||
int dvb_usbv2_generic_rw_locked(struct dvb_usb_device *d,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
return dvb_usb_v2_generic_io(d, wbuf, wlen, rbuf, rlen);
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usbv2_generic_rw_locked);
|
||||
|
||||
int dvb_usbv2_generic_write_locked(struct dvb_usb_device *d, u8 *buf, u16 len)
|
||||
{
|
||||
return dvb_usb_v2_generic_io(d, buf, len, NULL, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usbv2_generic_write_locked);
|
||||
460
drivers/media/usb/dvb-usb-v2/dvbsky.c
Normal file
460
drivers/media/usb/dvb-usb-v2/dvbsky.c
Normal file
|
|
@ -0,0 +1,460 @@
|
|||
/*
|
||||
* Driver for DVBSky USB2.0 receiver
|
||||
*
|
||||
* Copyright (C) 2013 Max nibble <nibble.max@gmail.com>
|
||||
*
|
||||
* 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 "m88ds3103.h"
|
||||
#include "m88ts2022.h"
|
||||
|
||||
#define DVBSKY_MSG_DELAY 0/*2000*/
|
||||
#define DVBSKY_BUF_LEN 64
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
struct dvbsky_state {
|
||||
struct mutex stream_mutex;
|
||||
u8 ibuf[DVBSKY_BUF_LEN];
|
||||
u8 obuf[DVBSKY_BUF_LEN];
|
||||
u8 last_lock;
|
||||
struct i2c_client *i2c_client_tuner;
|
||||
|
||||
/* fe hook functions*/
|
||||
int (*fe_set_voltage)(struct dvb_frontend *fe,
|
||||
fe_sec_voltage_t voltage);
|
||||
int (*fe_read_status)(struct dvb_frontend *fe,
|
||||
fe_status_t *status);
|
||||
};
|
||||
|
||||
static int dvbsky_usb_generic_rw(struct dvb_usb_device *d,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
int ret;
|
||||
struct dvbsky_state *state = d_to_priv(d);
|
||||
|
||||
mutex_lock(&d->usb_mutex);
|
||||
if (wlen != 0)
|
||||
memcpy(state->obuf, wbuf, wlen);
|
||||
|
||||
ret = dvb_usbv2_generic_rw_locked(d, state->obuf, wlen,
|
||||
state->ibuf, rlen);
|
||||
|
||||
if (!ret && (rlen != 0))
|
||||
memcpy(rbuf, state->ibuf, rlen);
|
||||
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dvbsky_stream_ctrl(struct dvb_usb_device *d, u8 onoff)
|
||||
{
|
||||
struct dvbsky_state *state = d_to_priv(d);
|
||||
int ret;
|
||||
u8 obuf_pre[3] = { 0x37, 0, 0 };
|
||||
u8 obuf_post[3] = { 0x36, 3, 0 };
|
||||
|
||||
mutex_lock(&state->stream_mutex);
|
||||
ret = dvbsky_usb_generic_rw(d, obuf_pre, 3, NULL, 0);
|
||||
if (!ret && onoff) {
|
||||
msleep(20);
|
||||
ret = dvbsky_usb_generic_rw(d, obuf_post, 3, NULL, 0);
|
||||
}
|
||||
mutex_unlock(&state->stream_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dvbsky_streaming_ctrl(struct dvb_frontend *fe, int onoff)
|
||||
{
|
||||
struct dvb_usb_device *d = fe_to_d(fe);
|
||||
|
||||
return dvbsky_stream_ctrl(d, (onoff == 0) ? 0 : 1);
|
||||
}
|
||||
|
||||
/* GPIO */
|
||||
static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value)
|
||||
{
|
||||
int ret;
|
||||
u8 obuf[3], ibuf[2];
|
||||
|
||||
obuf[0] = 0x0e;
|
||||
obuf[1] = gport;
|
||||
obuf[2] = value;
|
||||
ret = dvbsky_usb_generic_rw(d, obuf, 3, ibuf, 1);
|
||||
if (ret)
|
||||
dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
|
||||
KBUILD_MODNAME, __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int ret = 0;
|
||||
u8 ibuf[64], obuf[64];
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (num > 2) {
|
||||
dev_err(&d->udev->dev,
|
||||
"dvbsky_usb: too many i2c messages[%d] than 2.", num);
|
||||
ret = -EOPNOTSUPP;
|
||||
goto i2c_error;
|
||||
}
|
||||
|
||||
if (num == 1) {
|
||||
if (msg[0].len > 60) {
|
||||
dev_err(&d->udev->dev,
|
||||
"dvbsky_usb: too many i2c bytes[%d] than 60.",
|
||||
msg[0].len);
|
||||
ret = -EOPNOTSUPP;
|
||||
goto i2c_error;
|
||||
}
|
||||
if (msg[0].flags & I2C_M_RD) {
|
||||
/* single read */
|
||||
obuf[0] = 0x09;
|
||||
obuf[1] = 0;
|
||||
obuf[2] = msg[0].len;
|
||||
obuf[3] = msg[0].addr;
|
||||
ret = dvbsky_usb_generic_rw(d, obuf, 4,
|
||||
ibuf, msg[0].len + 1);
|
||||
if (ret)
|
||||
dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
|
||||
KBUILD_MODNAME, __func__, ret);
|
||||
if (!ret)
|
||||
memcpy(msg[0].buf, &ibuf[1], msg[0].len);
|
||||
} else {
|
||||
/* write */
|
||||
obuf[0] = 0x08;
|
||||
obuf[1] = msg[0].addr;
|
||||
obuf[2] = msg[0].len;
|
||||
memcpy(&obuf[3], msg[0].buf, msg[0].len);
|
||||
ret = dvbsky_usb_generic_rw(d, obuf,
|
||||
msg[0].len + 3, ibuf, 1);
|
||||
if (ret)
|
||||
dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
|
||||
KBUILD_MODNAME, __func__, ret);
|
||||
}
|
||||
} else {
|
||||
if ((msg[0].len > 60) || (msg[1].len > 60)) {
|
||||
dev_err(&d->udev->dev,
|
||||
"dvbsky_usb: too many i2c bytes[w-%d][r-%d] than 60.",
|
||||
msg[0].len, msg[1].len);
|
||||
ret = -EOPNOTSUPP;
|
||||
goto i2c_error;
|
||||
}
|
||||
/* write then read */
|
||||
obuf[0] = 0x09;
|
||||
obuf[1] = msg[0].len;
|
||||
obuf[2] = msg[1].len;
|
||||
obuf[3] = msg[0].addr;
|
||||
memcpy(&obuf[4], msg[0].buf, msg[0].len);
|
||||
ret = dvbsky_usb_generic_rw(d, obuf,
|
||||
msg[0].len + 4, ibuf, msg[1].len + 1);
|
||||
if (ret)
|
||||
dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
|
||||
KBUILD_MODNAME, __func__, ret);
|
||||
|
||||
if (!ret)
|
||||
memcpy(msg[1].buf, &ibuf[1], msg[1].len);
|
||||
}
|
||||
i2c_error:
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return (ret) ? ret : num;
|
||||
}
|
||||
|
||||
static u32 dvbsky_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm dvbsky_i2c_algo = {
|
||||
.master_xfer = dvbsky_i2c_xfer,
|
||||
.functionality = dvbsky_i2c_func,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_RC_CORE)
|
||||
static int dvbsky_rc_query(struct dvb_usb_device *d)
|
||||
{
|
||||
u32 code = 0xffff, scancode;
|
||||
u8 rc5_command, rc5_system;
|
||||
u8 obuf[2], ibuf[2], toggle;
|
||||
int ret;
|
||||
|
||||
obuf[0] = 0x10;
|
||||
ret = dvbsky_usb_generic_rw(d, obuf, 1, ibuf, 2);
|
||||
if (ret)
|
||||
dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
|
||||
KBUILD_MODNAME, __func__, ret);
|
||||
if (ret == 0)
|
||||
code = (ibuf[0] << 8) | ibuf[1];
|
||||
if (code != 0xffff) {
|
||||
dev_dbg(&d->udev->dev, "rc code: %x\n", code);
|
||||
rc5_command = code & 0x3F;
|
||||
rc5_system = (code & 0x7C0) >> 6;
|
||||
toggle = (code & 0x800) ? 1 : 0;
|
||||
scancode = rc5_system << 8 | rc5_command;
|
||||
rc_keydown(d->rc_dev, RC_TYPE_RC5, scancode, toggle);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvbsky_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
|
||||
{
|
||||
rc->allowed_protos = RC_BIT_RC5;
|
||||
rc->query = dvbsky_rc_query;
|
||||
rc->interval = 300;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define dvbsky_get_rc_config NULL
|
||||
#endif
|
||||
|
||||
static int dvbsky_usb_set_voltage(struct dvb_frontend *fe,
|
||||
fe_sec_voltage_t voltage)
|
||||
{
|
||||
struct dvb_usb_device *d = fe_to_d(fe);
|
||||
struct dvbsky_state *state = d_to_priv(d);
|
||||
u8 value;
|
||||
|
||||
if (voltage == SEC_VOLTAGE_OFF)
|
||||
value = 0;
|
||||
else
|
||||
value = 1;
|
||||
dvbsky_gpio_ctrl(d, 0x80, value);
|
||||
|
||||
return state->fe_set_voltage(fe, voltage);
|
||||
}
|
||||
|
||||
static int dvbsky_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
|
||||
{
|
||||
struct dvb_usb_device *d = adap_to_d(adap);
|
||||
u8 obuf[] = { 0x1e, 0x00 };
|
||||
u8 ibuf[6] = { 0 };
|
||||
struct i2c_msg msg[] = {
|
||||
{
|
||||
.addr = 0x51,
|
||||
.flags = 0,
|
||||
.buf = obuf,
|
||||
.len = 2,
|
||||
}, {
|
||||
.addr = 0x51,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = ibuf,
|
||||
.len = 6,
|
||||
}
|
||||
};
|
||||
|
||||
if (i2c_transfer(&d->i2c_adap, msg, 2) == 2)
|
||||
memcpy(mac, ibuf, 6);
|
||||
|
||||
dev_info(&d->udev->dev, "dvbsky_usb MAC address=%pM\n", mac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvbsky_usb_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct dvb_usb_device *d = fe_to_d(fe);
|
||||
struct dvbsky_state *state = d_to_priv(d);
|
||||
int ret;
|
||||
|
||||
ret = state->fe_read_status(fe, status);
|
||||
|
||||
/* it need resync slave fifo when signal change from unlock to lock.*/
|
||||
if ((*status & FE_HAS_LOCK) && (!state->last_lock))
|
||||
dvbsky_stream_ctrl(d, 1);
|
||||
|
||||
state->last_lock = (*status & FE_HAS_LOCK) ? 1 : 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct m88ds3103_config dvbsky_s960_m88ds3103_config = {
|
||||
.i2c_addr = 0x68,
|
||||
.clock = 27000000,
|
||||
.i2c_wr_max = 33,
|
||||
.clock_out = 0,
|
||||
.ts_mode = M88DS3103_TS_CI,
|
||||
.ts_clk = 16000,
|
||||
.ts_clk_pol = 0,
|
||||
.agc = 0x99,
|
||||
.lnb_hv_pol = 1,
|
||||
.lnb_en_pol = 1,
|
||||
};
|
||||
|
||||
static int dvbsky_s960_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dvbsky_state *state = adap_to_priv(adap);
|
||||
struct dvb_usb_device *d = adap_to_d(adap);
|
||||
int ret = 0;
|
||||
/* demod I2C adapter */
|
||||
struct i2c_adapter *i2c_adapter;
|
||||
struct i2c_client *client;
|
||||
struct i2c_board_info info;
|
||||
struct m88ts2022_config m88ts2022_config = {
|
||||
.clock = 27000000,
|
||||
};
|
||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
|
||||
/* attach demod */
|
||||
adap->fe[0] = dvb_attach(m88ds3103_attach,
|
||||
&dvbsky_s960_m88ds3103_config,
|
||||
&d->i2c_adap,
|
||||
&i2c_adapter);
|
||||
if (!adap->fe[0]) {
|
||||
dev_err(&d->udev->dev, "dvbsky_s960_attach fail.\n");
|
||||
ret = -ENODEV;
|
||||
goto fail_attach;
|
||||
}
|
||||
|
||||
/* attach tuner */
|
||||
m88ts2022_config.fe = adap->fe[0];
|
||||
strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
|
||||
info.addr = 0x60;
|
||||
info.platform_data = &m88ts2022_config;
|
||||
request_module("m88ts2022");
|
||||
client = i2c_new_device(i2c_adapter, &info);
|
||||
if (client == NULL || client->dev.driver == NULL) {
|
||||
dvb_frontend_detach(adap->fe[0]);
|
||||
ret = -ENODEV;
|
||||
goto fail_attach;
|
||||
}
|
||||
|
||||
if (!try_module_get(client->dev.driver->owner)) {
|
||||
i2c_unregister_device(client);
|
||||
dvb_frontend_detach(adap->fe[0]);
|
||||
ret = -ENODEV;
|
||||
goto fail_attach;
|
||||
}
|
||||
|
||||
/* delegate signal strength measurement to tuner */
|
||||
adap->fe[0]->ops.read_signal_strength =
|
||||
adap->fe[0]->ops.tuner_ops.get_rf_strength;
|
||||
|
||||
/* hook fe: need to resync the slave fifo when signal locks. */
|
||||
state->fe_read_status = adap->fe[0]->ops.read_status;
|
||||
adap->fe[0]->ops.read_status = dvbsky_usb_read_status;
|
||||
|
||||
/* hook fe: LNB off/on is control by Cypress usb chip. */
|
||||
state->fe_set_voltage = adap->fe[0]->ops.set_voltage;
|
||||
adap->fe[0]->ops.set_voltage = dvbsky_usb_set_voltage;
|
||||
|
||||
state->i2c_client_tuner = client;
|
||||
|
||||
fail_attach:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name)
|
||||
{
|
||||
dvbsky_gpio_ctrl(d, 0x04, 1);
|
||||
msleep(20);
|
||||
dvbsky_gpio_ctrl(d, 0x83, 0);
|
||||
dvbsky_gpio_ctrl(d, 0xc0, 1);
|
||||
msleep(100);
|
||||
dvbsky_gpio_ctrl(d, 0x83, 1);
|
||||
dvbsky_gpio_ctrl(d, 0xc0, 0);
|
||||
msleep(50);
|
||||
|
||||
return WARM;
|
||||
}
|
||||
|
||||
static int dvbsky_init(struct dvb_usb_device *d)
|
||||
{
|
||||
struct dvbsky_state *state = d_to_priv(d);
|
||||
|
||||
/* use default interface */
|
||||
/*
|
||||
ret = usb_set_interface(d->udev, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
*/
|
||||
mutex_init(&state->stream_mutex);
|
||||
|
||||
state->last_lock = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dvbsky_exit(struct dvb_usb_device *d)
|
||||
{
|
||||
struct dvbsky_state *state = d_to_priv(d);
|
||||
struct i2c_client *client;
|
||||
|
||||
client = state->i2c_client_tuner;
|
||||
/* remove I2C tuner */
|
||||
if (client) {
|
||||
module_put(client->dev.driver->owner);
|
||||
i2c_unregister_device(client);
|
||||
}
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties dvbsky_s960_props = {
|
||||
.driver_name = KBUILD_MODNAME,
|
||||
.owner = THIS_MODULE,
|
||||
.adapter_nr = adapter_nr,
|
||||
.size_of_priv = sizeof(struct dvbsky_state),
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
.generic_bulk_ctrl_endpoint_response = 0x81,
|
||||
.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
|
||||
|
||||
.i2c_algo = &dvbsky_i2c_algo,
|
||||
.frontend_attach = dvbsky_s960_attach,
|
||||
.init = dvbsky_init,
|
||||
.get_rc_config = dvbsky_get_rc_config,
|
||||
.streaming_ctrl = dvbsky_streaming_ctrl,
|
||||
.identify_state = dvbsky_identify_state,
|
||||
.exit = dvbsky_exit,
|
||||
.read_mac_address = dvbsky_read_mac_addr,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static const struct usb_device_id dvbsky_id_table[] = {
|
||||
{ DVB_USB_DEVICE(0x0572, 0x6831,
|
||||
&dvbsky_s960_props, "DVBSky S960/S860", RC_MAP_DVBSKY) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, dvbsky_id_table);
|
||||
|
||||
static struct usb_driver dvbsky_usb_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = dvbsky_id_table,
|
||||
.probe = dvb_usbv2_probe,
|
||||
.disconnect = dvb_usbv2_disconnect,
|
||||
.suspend = dvb_usbv2_suspend,
|
||||
.resume = dvb_usbv2_resume,
|
||||
.reset_resume = dvb_usbv2_reset_resume,
|
||||
.no_dynamic_id = 1,
|
||||
.soft_unbind = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(dvbsky_usb_driver);
|
||||
|
||||
MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
|
||||
MODULE_DESCRIPTION("Driver for DVBSky USB");
|
||||
MODULE_LICENSE("GPL");
|
||||
385
drivers/media/usb/dvb-usb-v2/ec168.c
Normal file
385
drivers/media/usb/dvb-usb-v2/ec168.c
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
/*
|
||||
* E3C EC168 DVB USB driver
|
||||
*
|
||||
* Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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 "ec168.h"
|
||||
#include "ec100.h"
|
||||
#include "mxl5005s.h"
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req)
|
||||
{
|
||||
int ret;
|
||||
unsigned int pipe;
|
||||
u8 request, requesttype;
|
||||
u8 *buf;
|
||||
|
||||
switch (req->cmd) {
|
||||
case DOWNLOAD_FIRMWARE:
|
||||
case GPIO:
|
||||
case WRITE_I2C:
|
||||
case STREAMING_CTRL:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
|
||||
request = req->cmd;
|
||||
break;
|
||||
case READ_I2C:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
|
||||
request = req->cmd;
|
||||
break;
|
||||
case GET_CONFIG:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
|
||||
request = CONFIG;
|
||||
break;
|
||||
case SET_CONFIG:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
|
||||
request = CONFIG;
|
||||
break;
|
||||
case WRITE_DEMOD:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
|
||||
request = DEMOD_RW;
|
||||
break;
|
||||
case READ_DEMOD:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
|
||||
request = DEMOD_RW;
|
||||
break;
|
||||
default:
|
||||
dev_err(&d->udev->dev, "%s: unknown command=%02x\n",
|
||||
KBUILD_MODNAME, req->cmd);
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
buf = kmalloc(req->size, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
|
||||
/* write */
|
||||
memcpy(buf, req->data, req->size);
|
||||
pipe = usb_sndctrlpipe(d->udev, 0);
|
||||
} else {
|
||||
/* read */
|
||||
pipe = usb_rcvctrlpipe(d->udev, 0);
|
||||
}
|
||||
|
||||
msleep(1); /* avoid I2C errors */
|
||||
|
||||
ret = usb_control_msg(d->udev, pipe, request, requesttype, req->value,
|
||||
req->index, buf, req->size, EC168_USB_TIMEOUT);
|
||||
|
||||
dvb_usb_dbg_usb_control_msg(d->udev, request, requesttype, req->value,
|
||||
req->index, buf, req->size);
|
||||
|
||||
if (ret < 0)
|
||||
goto err_dealloc;
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
/* read request, copy returned data to return buf */
|
||||
if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
|
||||
memcpy(req->data, buf, req->size);
|
||||
|
||||
kfree(buf);
|
||||
return ret;
|
||||
|
||||
err_dealloc:
|
||||
kfree(buf);
|
||||
error:
|
||||
dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static struct ec100_config ec168_ec100_config;
|
||||
|
||||
static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
struct ec168_req req;
|
||||
int i = 0;
|
||||
int ret;
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
while (i < num) {
|
||||
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (msg[i].addr == ec168_ec100_config.demod_address) {
|
||||
req.cmd = READ_DEMOD;
|
||||
req.value = 0;
|
||||
req.index = 0xff00 + msg[i].buf[0]; /* reg */
|
||||
req.size = msg[i+1].len; /* bytes to read */
|
||||
req.data = &msg[i+1].buf[0];
|
||||
ret = ec168_ctrl_msg(d, &req);
|
||||
i += 2;
|
||||
} else {
|
||||
dev_err(&d->udev->dev, "%s: I2C read not " \
|
||||
"implemented\n",
|
||||
KBUILD_MODNAME);
|
||||
ret = -EOPNOTSUPP;
|
||||
i += 2;
|
||||
}
|
||||
} else {
|
||||
if (msg[i].addr == ec168_ec100_config.demod_address) {
|
||||
req.cmd = WRITE_DEMOD;
|
||||
req.value = msg[i].buf[1]; /* val */
|
||||
req.index = 0xff00 + msg[i].buf[0]; /* reg */
|
||||
req.size = 0;
|
||||
req.data = NULL;
|
||||
ret = ec168_ctrl_msg(d, &req);
|
||||
i += 1;
|
||||
} else {
|
||||
req.cmd = WRITE_I2C;
|
||||
req.value = msg[i].buf[0]; /* val */
|
||||
req.index = 0x0100 + msg[i].addr; /* I2C addr */
|
||||
req.size = msg[i].len-1;
|
||||
req.data = &msg[i].buf[1];
|
||||
ret = ec168_ctrl_msg(d, &req);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
}
|
||||
ret = i;
|
||||
|
||||
error:
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 ec168_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm ec168_i2c_algo = {
|
||||
.master_xfer = ec168_i2c_xfer,
|
||||
.functionality = ec168_i2c_func,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int ec168_identify_state(struct dvb_usb_device *d, const char **name)
|
||||
{
|
||||
int ret;
|
||||
u8 reply;
|
||||
struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply};
|
||||
dev_dbg(&d->udev->dev, "%s:\n", __func__);
|
||||
|
||||
ret = ec168_ctrl_msg(d, &req);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
dev_dbg(&d->udev->dev, "%s: reply=%02x\n", __func__, reply);
|
||||
|
||||
if (reply == 0x01)
|
||||
ret = WARM;
|
||||
else
|
||||
ret = COLD;
|
||||
|
||||
return ret;
|
||||
error:
|
||||
dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ec168_download_firmware(struct dvb_usb_device *d,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
int ret, len, remaining;
|
||||
struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL};
|
||||
dev_dbg(&d->udev->dev, "%s:\n", __func__);
|
||||
|
||||
#define LEN_MAX 2048 /* max packet size */
|
||||
for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
|
||||
len = remaining;
|
||||
if (len > LEN_MAX)
|
||||
len = LEN_MAX;
|
||||
|
||||
req.size = len;
|
||||
req.data = (u8 *) &fw->data[fw->size - remaining];
|
||||
req.index = fw->size - remaining;
|
||||
|
||||
ret = ec168_ctrl_msg(d, &req);
|
||||
if (ret) {
|
||||
dev_err(&d->udev->dev,
|
||||
"%s: firmware download failed=%d\n",
|
||||
KBUILD_MODNAME, ret);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
req.size = 0;
|
||||
|
||||
/* set "warm"? */
|
||||
req.cmd = SET_CONFIG;
|
||||
req.value = 0;
|
||||
req.index = 0x0001;
|
||||
ret = ec168_ctrl_msg(d, &req);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* really needed - no idea what does */
|
||||
req.cmd = GPIO;
|
||||
req.value = 0;
|
||||
req.index = 0x0206;
|
||||
ret = ec168_ctrl_msg(d, &req);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* activate tuner I2C? */
|
||||
req.cmd = WRITE_I2C;
|
||||
req.value = 0;
|
||||
req.index = 0x00c6;
|
||||
ret = ec168_ctrl_msg(d, &req);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
return ret;
|
||||
error:
|
||||
dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ec100_config ec168_ec100_config = {
|
||||
.demod_address = 0xff, /* not real address, demod is integrated */
|
||||
};
|
||||
|
||||
static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dvb_usb_device *d = adap_to_d(adap);
|
||||
dev_dbg(&d->udev->dev, "%s:\n", __func__);
|
||||
|
||||
adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config,
|
||||
&d->i2c_adap);
|
||||
if (adap->fe[0] == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mxl5005s_config ec168_mxl5003s_config = {
|
||||
.i2c_address = 0xc6,
|
||||
.if_freq = IF_FREQ_4570000HZ,
|
||||
.xtal_freq = CRYSTAL_FREQ_16000000HZ,
|
||||
.agc_mode = MXL_SINGLE_AGC,
|
||||
.tracking_filter = MXL_TF_OFF,
|
||||
.rssi_enable = MXL_RSSI_ENABLE,
|
||||
.cap_select = MXL_CAP_SEL_ENABLE,
|
||||
.div_out = MXL_DIV_OUT_4,
|
||||
.clock_out = MXL_CLOCK_OUT_DISABLE,
|
||||
.output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
|
||||
.top = MXL5005S_TOP_25P2,
|
||||
.mod_mode = MXL_DIGITAL_MODE,
|
||||
.if_mode = MXL_ZERO_IF,
|
||||
.AgcMasterByte = 0x00,
|
||||
};
|
||||
|
||||
static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dvb_usb_device *d = adap_to_d(adap);
|
||||
dev_dbg(&d->udev->dev, "%s:\n", __func__);
|
||||
|
||||
return dvb_attach(mxl5005s_attach, adap->fe[0], &d->i2c_adap,
|
||||
&ec168_mxl5003s_config) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
static int ec168_streaming_ctrl(struct dvb_frontend *fe, int onoff)
|
||||
{
|
||||
struct dvb_usb_device *d = fe_to_d(fe);
|
||||
struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL};
|
||||
dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
|
||||
|
||||
if (onoff)
|
||||
req.index = 0x0102;
|
||||
return ec168_ctrl_msg(d, &req);
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
/* bInterfaceNumber 0 is HID
|
||||
* bInterfaceNumber 1 is DVB-T */
|
||||
static struct dvb_usb_device_properties ec168_props = {
|
||||
.driver_name = KBUILD_MODNAME,
|
||||
.owner = THIS_MODULE,
|
||||
.adapter_nr = adapter_nr,
|
||||
.bInterfaceNumber = 1,
|
||||
|
||||
.identify_state = ec168_identify_state,
|
||||
.firmware = EC168_FIRMWARE,
|
||||
.download_firmware = ec168_download_firmware,
|
||||
|
||||
.i2c_algo = &ec168_i2c_algo,
|
||||
.frontend_attach = ec168_ec100_frontend_attach,
|
||||
.tuner_attach = ec168_mxl5003s_tuner_attach,
|
||||
.streaming_ctrl = ec168_streaming_ctrl,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.stream = DVB_USB_STREAM_BULK(0x82, 6, 32 * 512),
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
static const struct dvb_usb_driver_info ec168_driver_info = {
|
||||
.name = "E3C EC168 reference design",
|
||||
.props = &ec168_props,
|
||||
};
|
||||
|
||||
static const struct usb_device_id ec168_id[] = {
|
||||
{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168),
|
||||
.driver_info = (kernel_ulong_t) &ec168_driver_info },
|
||||
{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2),
|
||||
.driver_info = (kernel_ulong_t) &ec168_driver_info },
|
||||
{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3),
|
||||
.driver_info = (kernel_ulong_t) &ec168_driver_info },
|
||||
{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4),
|
||||
.driver_info = (kernel_ulong_t) &ec168_driver_info },
|
||||
{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5),
|
||||
.driver_info = (kernel_ulong_t) &ec168_driver_info },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, ec168_id);
|
||||
|
||||
static struct usb_driver ec168_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = ec168_id,
|
||||
.probe = dvb_usbv2_probe,
|
||||
.disconnect = dvb_usbv2_disconnect,
|
||||
.suspend = dvb_usbv2_suspend,
|
||||
.resume = dvb_usbv2_resume,
|
||||
.no_dynamic_id = 1,
|
||||
.soft_unbind = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(ec168_driver);
|
||||
|
||||
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
|
||||
MODULE_DESCRIPTION("E3C EC168 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_FIRMWARE(EC168_FIRMWARE);
|
||||
53
drivers/media/usb/dvb-usb-v2/ec168.h
Normal file
53
drivers/media/usb/dvb-usb-v2/ec168.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* E3C EC168 DVB USB driver
|
||||
*
|
||||
* Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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 EC168_H
|
||||
#define EC168_H
|
||||
|
||||
#include "dvb_usb.h"
|
||||
|
||||
#define EC168_USB_TIMEOUT 1000
|
||||
#define EC168_FIRMWARE "dvb-usb-ec168.fw"
|
||||
|
||||
struct ec168_req {
|
||||
u8 cmd; /* [1] */
|
||||
u16 value; /* [2|3] */
|
||||
u16 index; /* [4|5] */
|
||||
u16 size; /* [6|7] */
|
||||
u8 *data;
|
||||
};
|
||||
|
||||
enum ec168_cmd {
|
||||
DOWNLOAD_FIRMWARE = 0x00,
|
||||
CONFIG = 0x01,
|
||||
DEMOD_RW = 0x03,
|
||||
GPIO = 0x04,
|
||||
STREAMING_CTRL = 0x10,
|
||||
READ_I2C = 0x20,
|
||||
WRITE_I2C = 0x21,
|
||||
HID_DOWNLOAD = 0x30,
|
||||
GET_CONFIG,
|
||||
SET_CONFIG,
|
||||
READ_DEMOD,
|
||||
WRITE_DEMOD,
|
||||
};
|
||||
|
||||
#endif
|
||||
177
drivers/media/usb/dvb-usb-v2/gl861.c
Normal file
177
drivers/media/usb/dvb-usb-v2/gl861.c
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/* DVB USB compliant linux driver for GL861 USB2.0 devices.
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "gl861.h"
|
||||
|
||||
#include "zl10353.h"
|
||||
#include "qt1010.h"
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u16 index;
|
||||
u16 value = addr << (8 + 1);
|
||||
int wo = (rbuf == NULL || rlen == 0); /* write-only */
|
||||
u8 req, type;
|
||||
|
||||
if (wo) {
|
||||
req = GL861_REQ_I2C_WRITE;
|
||||
type = GL861_WRITE;
|
||||
} else { /* rw */
|
||||
req = GL861_REQ_I2C_READ;
|
||||
type = GL861_READ;
|
||||
}
|
||||
|
||||
switch (wlen) {
|
||||
case 1:
|
||||
index = wbuf[0];
|
||||
break;
|
||||
case 2:
|
||||
index = wbuf[0];
|
||||
value = value + wbuf[1];
|
||||
break;
|
||||
default:
|
||||
dev_err(&d->udev->dev, "%s: wlen=%d, aborting\n",
|
||||
KBUILD_MODNAME, wlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msleep(1); /* avoid I2C errors */
|
||||
|
||||
return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
|
||||
value, index, rbuf, rlen, 2000);
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
|
||||
break;
|
||||
i++;
|
||||
} else
|
||||
if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, NULL, 0) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 gl861_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm gl861_i2c_algo = {
|
||||
.master_xfer = gl861_i2c_xfer,
|
||||
.functionality = gl861_i2c_func,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static struct zl10353_config gl861_zl10353_config = {
|
||||
.demod_address = 0x0f,
|
||||
.no_tuner = 1,
|
||||
.parallel_ts = 1,
|
||||
};
|
||||
|
||||
static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
|
||||
adap->fe[0] = dvb_attach(zl10353_attach, &gl861_zl10353_config,
|
||||
&adap_to_d(adap)->i2c_adap);
|
||||
if (adap->fe[0] == NULL)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct qt1010_config gl861_qt1010_config = {
|
||||
.i2c_address = 0x62
|
||||
};
|
||||
|
||||
static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
return dvb_attach(qt1010_attach,
|
||||
adap->fe[0], &adap_to_d(adap)->i2c_adap,
|
||||
&gl861_qt1010_config) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
static int gl861_init(struct dvb_usb_device *d)
|
||||
{
|
||||
/*
|
||||
* There is 2 interfaces. Interface 0 is for TV and interface 1 is
|
||||
* for HID remote controller. Interface 0 has 2 alternate settings.
|
||||
* For some reason we need to set interface explicitly, defaulted
|
||||
* as alternate setting 1?
|
||||
*/
|
||||
return usb_set_interface(d->udev, 0, 0);
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties gl861_props = {
|
||||
.driver_name = KBUILD_MODNAME,
|
||||
.owner = THIS_MODULE,
|
||||
.adapter_nr = adapter_nr,
|
||||
|
||||
.i2c_algo = &gl861_i2c_algo,
|
||||
.frontend_attach = gl861_frontend_attach,
|
||||
.tuner_attach = gl861_tuner_attach,
|
||||
.init = gl861_init,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.stream = DVB_USB_STREAM_BULK(0x81, 7, 512),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static const struct usb_device_id gl861_id_table[] = {
|
||||
{ DVB_USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801,
|
||||
&gl861_props, "MSI Mega Sky 55801 DVB-T USB2.0", NULL) },
|
||||
{ DVB_USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU,
|
||||
&gl861_props, "A-LINK DTU DVB-T USB2.0", NULL) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, gl861_id_table);
|
||||
|
||||
static struct usb_driver gl861_usb_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = gl861_id_table,
|
||||
.probe = dvb_usbv2_probe,
|
||||
.disconnect = dvb_usbv2_disconnect,
|
||||
.suspend = dvb_usbv2_suspend,
|
||||
.resume = dvb_usbv2_resume,
|
||||
.reset_resume = dvb_usbv2_reset_resume,
|
||||
.no_dynamic_id = 1,
|
||||
.soft_unbind = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(gl861_usb_driver);
|
||||
|
||||
MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
|
||||
MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
||||
12
drivers/media/usb/dvb-usb-v2/gl861.h
Normal file
12
drivers/media/usb/dvb-usb-v2/gl861.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef _DVB_USB_GL861_H_
|
||||
#define _DVB_USB_GL861_H_
|
||||
|
||||
#include "dvb_usb.h"
|
||||
|
||||
#define GL861_WRITE 0x40
|
||||
#define GL861_READ 0xc0
|
||||
|
||||
#define GL861_REQ_I2C_WRITE 0x01
|
||||
#define GL861_REQ_I2C_READ 0x02
|
||||
|
||||
#endif
|
||||
1389
drivers/media/usb/dvb-usb-v2/lmedm04.c
Normal file
1389
drivers/media/usb/dvb-usb-v2/lmedm04.c
Normal file
File diff suppressed because it is too large
Load diff
175
drivers/media/usb/dvb-usb-v2/lmedm04.h
Normal file
175
drivers/media/usb/dvb-usb-v2/lmedm04.h
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/* DVB USB compliant linux driver for
|
||||
*
|
||||
* DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395
|
||||
* LME2510C + LG TDQY-P001F
|
||||
* LME2510 + LG TDQY-P001F
|
||||
*
|
||||
* MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
|
||||
* SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
|
||||
*
|
||||
* MVB001F (LME2510+LGTDQT-P001F)
|
||||
* LG TDQY - P001F =(TDA8263 + TDA10086H)
|
||||
*
|
||||
* MVB0001F (LME2510C+LGTDQT-P001F)
|
||||
*
|
||||
* 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, version 2.
|
||||
* *
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#ifndef _DVB_USB_LME2510_H_
|
||||
#define _DVB_USB_LME2510_H_
|
||||
|
||||
/* Streamer & PID
|
||||
*
|
||||
* Note: These commands do not actually stop the streaming
|
||||
* but form some kind of packet filtering/stream count
|
||||
* or tuning related functions.
|
||||
* 06 XX
|
||||
* offset 1 = 00 Enable Streaming
|
||||
*
|
||||
*
|
||||
* PID
|
||||
* 03 XX XX ----> reg number ---> setting....20 XX
|
||||
* offset 1 = length
|
||||
* offset 2 = start of data
|
||||
* end byte -1 = 20
|
||||
* end byte = clear pid always a0, other wise 9c, 9a ??
|
||||
*
|
||||
*/
|
||||
#define LME_ST_ON_W {0x06, 0x00}
|
||||
#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0}
|
||||
#define LME_ZERO_PID {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c}
|
||||
#define LME_ALL_PIDS {0x03, 0x06, 0x00, 0xff, 0x01, 0x1f, 0x20, 0x81}
|
||||
|
||||
/* LNB Voltage
|
||||
* 07 XX XX
|
||||
* offset 1 = 01
|
||||
* offset 2 = 00=Voltage low 01=Voltage high
|
||||
*
|
||||
* LNB Power
|
||||
* 03 01 XX
|
||||
* offset 2 = 00=ON 01=OFF
|
||||
*/
|
||||
|
||||
#define LME_VOLTAGE_L {0x07, 0x01, 0x00}
|
||||
#define LME_VOLTAGE_H {0x07, 0x01, 0x01}
|
||||
#define LNB_ON {0x3a, 0x01, 0x00}
|
||||
#define LNB_OFF {0x3a, 0x01, 0x01}
|
||||
|
||||
/* Initial stv0288 settings for 7395 Frontend */
|
||||
static u8 s7395_inittab[] = {
|
||||
0x01, 0x15,
|
||||
0x02, 0x20,
|
||||
0x03, 0xa0,
|
||||
0x04, 0xa0,
|
||||
0x05, 0x12,
|
||||
0x06, 0x00,
|
||||
0x09, 0x00,
|
||||
0x0a, 0x04,
|
||||
0x0b, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x0d, 0x00,
|
||||
0x0e, 0xc1,
|
||||
0x0f, 0x54,
|
||||
0x11, 0x7a,
|
||||
0x12, 0x03,
|
||||
0x13, 0x48,
|
||||
0x14, 0x84,
|
||||
0x15, 0xc5,
|
||||
0x16, 0xb8,
|
||||
0x17, 0x9c,
|
||||
0x18, 0x00,
|
||||
0x19, 0xa6,
|
||||
0x1a, 0x88,
|
||||
0x1b, 0x8f,
|
||||
0x1c, 0xf0,
|
||||
0x20, 0x0b,
|
||||
0x21, 0x54,
|
||||
0x22, 0xff,
|
||||
0x23, 0x01,
|
||||
0x28, 0x46,
|
||||
0x29, 0x66,
|
||||
0x2a, 0x90,
|
||||
0x2b, 0xfa,
|
||||
0x2c, 0xd9,
|
||||
0x30, 0x0,
|
||||
0x31, 0x1e,
|
||||
0x32, 0x14,
|
||||
0x33, 0x0f,
|
||||
0x34, 0x09,
|
||||
0x35, 0x0c,
|
||||
0x36, 0x05,
|
||||
0x37, 0x2f,
|
||||
0x38, 0x16,
|
||||
0x39, 0xbd,
|
||||
0x3a, 0x0,
|
||||
0x3b, 0x13,
|
||||
0x3c, 0x11,
|
||||
0x3d, 0x30,
|
||||
0x40, 0x63,
|
||||
0x41, 0x04,
|
||||
0x42, 0x20,
|
||||
0x43, 0x00,
|
||||
0x44, 0x00,
|
||||
0x45, 0x00,
|
||||
0x46, 0x00,
|
||||
0x47, 0x00,
|
||||
0x4a, 0x00,
|
||||
0x50, 0x10,
|
||||
0x51, 0x36,
|
||||
0x52, 0x21,
|
||||
0x53, 0x94,
|
||||
0x54, 0xb2,
|
||||
0x55, 0x29,
|
||||
0x56, 0x64,
|
||||
0x57, 0x2b,
|
||||
0x58, 0x54,
|
||||
0x59, 0x86,
|
||||
0x5a, 0x00,
|
||||
0x5b, 0x9b,
|
||||
0x5c, 0x08,
|
||||
0x5d, 0x7f,
|
||||
0x5e, 0xff,
|
||||
0x5f, 0x8d,
|
||||
0x70, 0x0,
|
||||
0x71, 0x0,
|
||||
0x72, 0x0,
|
||||
0x74, 0x0,
|
||||
0x75, 0x0,
|
||||
0x76, 0x0,
|
||||
0x81, 0x0,
|
||||
0x82, 0x3f,
|
||||
0x83, 0x3f,
|
||||
0x84, 0x0,
|
||||
0x85, 0x0,
|
||||
0x88, 0x0,
|
||||
0x89, 0x0,
|
||||
0x8a, 0x0,
|
||||
0x8b, 0x0,
|
||||
0x8c, 0x0,
|
||||
0x90, 0x0,
|
||||
0x91, 0x0,
|
||||
0x92, 0x0,
|
||||
0x93, 0x0,
|
||||
0x94, 0x1c,
|
||||
0x97, 0x0,
|
||||
0xa0, 0x48,
|
||||
0xa1, 0x0,
|
||||
0xb0, 0xb8,
|
||||
0xb1, 0x3a,
|
||||
0xb2, 0x10,
|
||||
0xb3, 0x82,
|
||||
0xb4, 0x80,
|
||||
0xb5, 0x82,
|
||||
0xb6, 0x82,
|
||||
0xb7, 0x82,
|
||||
0xb8, 0x20,
|
||||
0xb9, 0x0,
|
||||
0xf0, 0x0,
|
||||
0xf1, 0x0,
|
||||
0xf2, 0xc0,
|
||||
0xff, 0xff,
|
||||
};
|
||||
#endif
|
||||
612
drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
Normal file
612
drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
Normal file
|
|
@ -0,0 +1,612 @@
|
|||
/*
|
||||
* mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator
|
||||
*
|
||||
* Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* 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 "mxl111sf-demod.h"
|
||||
#include "mxl111sf-reg.h"
|
||||
|
||||
/* debug */
|
||||
static int mxl111sf_demod_debug;
|
||||
module_param_named(debug, mxl111sf_demod_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
|
||||
|
||||
#define mxl_dbg(fmt, arg...) \
|
||||
if (mxl111sf_demod_debug) \
|
||||
mxl_printk(KERN_DEBUG, fmt, ##arg)
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
struct mxl111sf_demod_state {
|
||||
struct mxl111sf_state *mxl_state;
|
||||
|
||||
struct mxl111sf_demod_config *cfg;
|
||||
|
||||
struct dvb_frontend fe;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static int mxl111sf_demod_read_reg(struct mxl111sf_demod_state *state,
|
||||
u8 addr, u8 *data)
|
||||
{
|
||||
return (state->cfg->read_reg) ?
|
||||
state->cfg->read_reg(state->mxl_state, addr, data) :
|
||||
-EINVAL;
|
||||
}
|
||||
|
||||
static int mxl111sf_demod_write_reg(struct mxl111sf_demod_state *state,
|
||||
u8 addr, u8 data)
|
||||
{
|
||||
return (state->cfg->write_reg) ?
|
||||
state->cfg->write_reg(state->mxl_state, addr, data) :
|
||||
-EINVAL;
|
||||
}
|
||||
|
||||
static
|
||||
int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state,
|
||||
struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
|
||||
{
|
||||
return (state->cfg->program_regs) ?
|
||||
state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
|
||||
-EINVAL;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* TPS */
|
||||
|
||||
static
|
||||
int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state,
|
||||
fe_code_rate_t *code_rate)
|
||||
{
|
||||
u8 val;
|
||||
int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val);
|
||||
/* bit<2:0> - 000:1/2, 001:2/3, 010:3/4, 011:5/6, 100:7/8 */
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
switch (val & V6_CODE_RATE_TPS_MASK) {
|
||||
case 0:
|
||||
*code_rate = FEC_1_2;
|
||||
break;
|
||||
case 1:
|
||||
*code_rate = FEC_2_3;
|
||||
break;
|
||||
case 2:
|
||||
*code_rate = FEC_3_4;
|
||||
break;
|
||||
case 3:
|
||||
*code_rate = FEC_5_6;
|
||||
break;
|
||||
case 4:
|
||||
*code_rate = FEC_7_8;
|
||||
break;
|
||||
}
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int mxl1x1sf_demod_get_tps_modulation(struct mxl111sf_demod_state *state,
|
||||
fe_modulation_t *modulation)
|
||||
{
|
||||
u8 val;
|
||||
int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val);
|
||||
/* Constellation, 00 : QPSK, 01 : 16QAM, 10:64QAM */
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) {
|
||||
case 0:
|
||||
*modulation = QPSK;
|
||||
break;
|
||||
case 1:
|
||||
*modulation = QAM_16;
|
||||
break;
|
||||
case 2:
|
||||
*modulation = QAM_64;
|
||||
break;
|
||||
}
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state,
|
||||
fe_transmit_mode_t *fft_mode)
|
||||
{
|
||||
u8 val;
|
||||
int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val);
|
||||
/* FFT Mode, 00:2K, 01:8K, 10:4K */
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
switch ((val & V6_PARAM_FFT_MODE_MASK) >> 2) {
|
||||
case 0:
|
||||
*fft_mode = TRANSMISSION_MODE_2K;
|
||||
break;
|
||||
case 1:
|
||||
*fft_mode = TRANSMISSION_MODE_8K;
|
||||
break;
|
||||
case 2:
|
||||
*fft_mode = TRANSMISSION_MODE_4K;
|
||||
break;
|
||||
}
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state,
|
||||
fe_guard_interval_t *guard)
|
||||
{
|
||||
u8 val;
|
||||
int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val);
|
||||
/* 00:1/32, 01:1/16, 10:1/8, 11:1/4 */
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
switch ((val & V6_PARAM_GI_MASK) >> 4) {
|
||||
case 0:
|
||||
*guard = GUARD_INTERVAL_1_32;
|
||||
break;
|
||||
case 1:
|
||||
*guard = GUARD_INTERVAL_1_16;
|
||||
break;
|
||||
case 2:
|
||||
*guard = GUARD_INTERVAL_1_8;
|
||||
break;
|
||||
case 3:
|
||||
*guard = GUARD_INTERVAL_1_4;
|
||||
break;
|
||||
}
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state,
|
||||
fe_hierarchy_t *hierarchy)
|
||||
{
|
||||
u8 val;
|
||||
int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val);
|
||||
/* bit<6:4> - 000:Non hierarchy, 001:1, 010:2, 011:4 */
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
switch ((val & V6_TPS_HIERARCHY_INFO_MASK) >> 6) {
|
||||
case 0:
|
||||
*hierarchy = HIERARCHY_NONE;
|
||||
break;
|
||||
case 1:
|
||||
*hierarchy = HIERARCHY_1;
|
||||
break;
|
||||
case 2:
|
||||
*hierarchy = HIERARCHY_2;
|
||||
break;
|
||||
case 3:
|
||||
*hierarchy = HIERARCHY_4;
|
||||
break;
|
||||
}
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* LOCKS */
|
||||
|
||||
static
|
||||
int mxl1x1sf_demod_get_sync_lock_status(struct mxl111sf_demod_state *state,
|
||||
int *sync_lock)
|
||||
{
|
||||
u8 val = 0;
|
||||
int ret = mxl111sf_demod_read_reg(state, V6_SYNC_LOCK_REG, &val);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
*sync_lock = (val & SYNC_LOCK_MASK) >> 4;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int mxl1x1sf_demod_get_rs_lock_status(struct mxl111sf_demod_state *state,
|
||||
int *rs_lock)
|
||||
{
|
||||
u8 val = 0;
|
||||
int ret = mxl111sf_demod_read_reg(state, V6_RS_LOCK_DET_REG, &val);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
*rs_lock = (val & RS_LOCK_DET_MASK) >> 3;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int mxl1x1sf_demod_get_tps_lock_status(struct mxl111sf_demod_state *state,
|
||||
int *tps_lock)
|
||||
{
|
||||
u8 val = 0;
|
||||
int ret = mxl111sf_demod_read_reg(state, V6_TPS_LOCK_REG, &val);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
*tps_lock = (val & V6_PARAM_TPS_LOCK_MASK) >> 6;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int mxl1x1sf_demod_get_fec_lock_status(struct mxl111sf_demod_state *state,
|
||||
int *fec_lock)
|
||||
{
|
||||
u8 val = 0;
|
||||
int ret = mxl111sf_demod_read_reg(state, V6_IRQ_STATUS_REG, &val);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
*fec_lock = (val & IRQ_MASK_FEC_LOCK) >> 4;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static
|
||||
int mxl1x1sf_demod_get_cp_lock_status(struct mxl111sf_demod_state *state,
|
||||
int *cp_lock)
|
||||
{
|
||||
u8 val = 0;
|
||||
int ret = mxl111sf_demod_read_reg(state, V6_CP_LOCK_DET_REG, &val);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
*cp_lock = (val & V6_CP_LOCK_DET_MASK) >> 2;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state)
|
||||
{
|
||||
return mxl111sf_demod_write_reg(state, 0x0e, 0xff);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct mxl111sf_demod_state *state = fe->demodulator_priv;
|
||||
int ret = 0;
|
||||
|
||||
struct mxl111sf_reg_ctrl_info phy_pll_patch[] = {
|
||||
{0x00, 0xff, 0x01}, /* change page to 1 */
|
||||
{0x40, 0xff, 0x05},
|
||||
{0x40, 0xff, 0x01},
|
||||
{0x41, 0xff, 0xca},
|
||||
{0x41, 0xff, 0xc0},
|
||||
{0x00, 0xff, 0x00}, /* change page to 0 */
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
mxl_dbg("()");
|
||||
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
ret = fe->ops.tuner_ops.set_params(fe);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
msleep(50);
|
||||
}
|
||||
ret = mxl111sf_demod_program_regs(state, phy_pll_patch);
|
||||
mxl_fail(ret);
|
||||
msleep(50);
|
||||
ret = mxl1x1sf_demod_reset_irq_status(state);
|
||||
mxl_fail(ret);
|
||||
msleep(100);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#if 0
|
||||
/* resets TS Packet error count */
|
||||
/* After setting 7th bit of V5_PER_COUNT_RESET_REG, it should be reset to 0. */
|
||||
static
|
||||
int mxl1x1sf_demod_reset_packet_error_count(struct mxl111sf_demod_state *state)
|
||||
{
|
||||
struct mxl111sf_reg_ctrl_info reset_per_count[] = {
|
||||
{0x20, 0x01, 0x01},
|
||||
{0x20, 0x01, 0x00},
|
||||
{0, 0, 0}
|
||||
};
|
||||
return mxl111sf_demod_program_regs(state, reset_per_count);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* returns TS Packet error count */
|
||||
/* PER Count = FEC_PER_COUNT * (2 ** (FEC_PER_SCALE * 4)) */
|
||||
static int mxl111sf_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
struct mxl111sf_demod_state *state = fe->demodulator_priv;
|
||||
u32 fec_per_count, fec_per_scale;
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
*ucblocks = 0;
|
||||
|
||||
/* FEC_PER_COUNT Register */
|
||||
ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_COUNT_REG, &val);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
fec_per_count = val;
|
||||
|
||||
/* FEC_PER_SCALE Register */
|
||||
ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_SCALE_REG, &val);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
val &= V6_FEC_PER_SCALE_MASK;
|
||||
val *= 4;
|
||||
|
||||
fec_per_scale = 1 << val;
|
||||
|
||||
fec_per_count *= fec_per_scale;
|
||||
|
||||
*ucblocks = fec_per_count;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef MXL111SF_DEMOD_ENABLE_CALCULATIONS
|
||||
/* FIXME: leaving this enabled breaks the build on some architectures,
|
||||
* and we shouldn't have any floating point math in the kernel, anyway.
|
||||
*
|
||||
* These macros need to be re-written, but it's harmless to simply
|
||||
* return zero for now. */
|
||||
#define CALCULATE_BER(avg_errors, count) \
|
||||
((u32)(avg_errors * 4)/(count*64*188*8))
|
||||
#define CALCULATE_SNR(data) \
|
||||
((u32)((10 * (u32)data / 64) - 2.5))
|
||||
#else
|
||||
#define CALCULATE_BER(avg_errors, count) 0
|
||||
#define CALCULATE_SNR(data) 0
|
||||
#endif
|
||||
|
||||
static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct mxl111sf_demod_state *state = fe->demodulator_priv;
|
||||
u8 val1, val2, val3;
|
||||
int ret;
|
||||
|
||||
*ber = 0;
|
||||
|
||||
ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_LSB_REG, &val1);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_MSB_REG, &val2);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_demod_read_reg(state, V6_N_ACCUMULATE_REG, &val3);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
*ber = CALCULATE_BER((val1 | (val2 << 8)), val3);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_demod_calc_snr(struct mxl111sf_demod_state *state,
|
||||
u16 *snr)
|
||||
{
|
||||
u8 val1, val2;
|
||||
int ret;
|
||||
|
||||
*snr = 0;
|
||||
|
||||
ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_LSB_REG, &val1);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_MSB_REG, &val2);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
*snr = CALCULATE_SNR(val1 | ((val2 & 0x03) << 8));
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_demod_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct mxl111sf_demod_state *state = fe->demodulator_priv;
|
||||
|
||||
int ret = mxl111sf_demod_calc_snr(state, snr);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
*snr /= 10; /* 0.1 dB */
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_demod_read_status(struct dvb_frontend *fe,
|
||||
fe_status_t *status)
|
||||
{
|
||||
struct mxl111sf_demod_state *state = fe->demodulator_priv;
|
||||
int ret, locked, cr_lock, sync_lock, fec_lock;
|
||||
|
||||
*status = 0;
|
||||
|
||||
ret = mxl1x1sf_demod_get_rs_lock_status(state, &locked);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl1x1sf_demod_get_tps_lock_status(state, &cr_lock);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl1x1sf_demod_get_sync_lock_status(state, &sync_lock);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl1x1sf_demod_get_fec_lock_status(state, &fec_lock);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
if (locked)
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
if (cr_lock)
|
||||
*status |= FE_HAS_CARRIER;
|
||||
if (sync_lock)
|
||||
*status |= FE_HAS_SYNC;
|
||||
if (fec_lock) /* false positives? */
|
||||
*status |= FE_HAS_VITERBI;
|
||||
|
||||
if ((locked) && (cr_lock) && (sync_lock))
|
||||
*status |= FE_HAS_LOCK;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe,
|
||||
u16 *signal_strength)
|
||||
{
|
||||
struct mxl111sf_demod_state *state = fe->demodulator_priv;
|
||||
fe_modulation_t modulation;
|
||||
u16 snr;
|
||||
|
||||
mxl111sf_demod_calc_snr(state, &snr);
|
||||
mxl1x1sf_demod_get_tps_modulation(state, &modulation);
|
||||
|
||||
switch (modulation) {
|
||||
case QPSK:
|
||||
*signal_strength = (snr >= 1300) ?
|
||||
min(65535, snr * 44) : snr * 38;
|
||||
break;
|
||||
case QAM_16:
|
||||
*signal_strength = (snr >= 1500) ?
|
||||
min(65535, snr * 38) : snr * 33;
|
||||
break;
|
||||
case QAM_64:
|
||||
*signal_strength = (snr >= 2000) ?
|
||||
min(65535, snr * 29) : snr * 25;
|
||||
break;
|
||||
default:
|
||||
*signal_strength = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
struct mxl111sf_demod_state *state = fe->demodulator_priv;
|
||||
|
||||
mxl_dbg("()");
|
||||
#if 0
|
||||
p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF;
|
||||
#endif
|
||||
if (fe->ops.tuner_ops.get_bandwidth)
|
||||
fe->ops.tuner_ops.get_bandwidth(fe, &p->bandwidth_hz);
|
||||
if (fe->ops.tuner_ops.get_frequency)
|
||||
fe->ops.tuner_ops.get_frequency(fe, &p->frequency);
|
||||
mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_HP);
|
||||
mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_LP);
|
||||
mxl1x1sf_demod_get_tps_modulation(state, &p->modulation);
|
||||
mxl1x1sf_demod_get_tps_guard_fft_mode(state,
|
||||
&p->transmission_mode);
|
||||
mxl1x1sf_demod_get_tps_guard_interval(state,
|
||||
&p->guard_interval);
|
||||
mxl1x1sf_demod_get_tps_hierarchy(state,
|
||||
&p->hierarchy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int mxl111sf_demod_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *tune)
|
||||
{
|
||||
tune->min_delay_ms = 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mxl111sf_demod_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct mxl111sf_demod_state *state = fe->demodulator_priv;
|
||||
mxl_dbg("()");
|
||||
kfree(state);
|
||||
fe->demodulator_priv = NULL;
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops mxl111sf_demod_ops = {
|
||||
.delsys = { SYS_DVBT },
|
||||
.info = {
|
||||
.name = "MaxLinear MxL111SF DVB-T demodulator",
|
||||
.frequency_min = 177000000,
|
||||
.frequency_max = 858000000,
|
||||
.frequency_stepsize = 166666,
|
||||
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
|
||||
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
|
||||
FE_CAN_QAM_AUTO |
|
||||
FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
|
||||
},
|
||||
.release = mxl111sf_demod_release,
|
||||
#if 0
|
||||
.init = mxl111sf_init,
|
||||
.i2c_gate_ctrl = mxl111sf_i2c_gate_ctrl,
|
||||
#endif
|
||||
.set_frontend = mxl111sf_demod_set_frontend,
|
||||
.get_frontend = mxl111sf_demod_get_frontend,
|
||||
.get_tune_settings = mxl111sf_demod_get_tune_settings,
|
||||
.read_status = mxl111sf_demod_read_status,
|
||||
.read_signal_strength = mxl111sf_demod_read_signal_strength,
|
||||
.read_ber = mxl111sf_demod_read_ber,
|
||||
.read_snr = mxl111sf_demod_read_snr,
|
||||
.read_ucblocks = mxl111sf_demod_read_ucblocks,
|
||||
};
|
||||
|
||||
struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
|
||||
struct mxl111sf_demod_config *cfg)
|
||||
{
|
||||
struct mxl111sf_demod_state *state = NULL;
|
||||
|
||||
mxl_dbg("()");
|
||||
|
||||
state = kzalloc(sizeof(struct mxl111sf_demod_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
return NULL;
|
||||
|
||||
state->mxl_state = mxl_state;
|
||||
state->cfg = cfg;
|
||||
|
||||
memcpy(&state->fe.ops, &mxl111sf_demod_ops,
|
||||
sizeof(struct dvb_frontend_ops));
|
||||
|
||||
state->fe.demodulator_priv = state;
|
||||
return &state->fe;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mxl111sf_demod_attach);
|
||||
|
||||
MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver");
|
||||
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("0.1");
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
55
drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
Normal file
55
drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator
|
||||
*
|
||||
* Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* 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 __MXL111SF_DEMOD_H__
|
||||
#define __MXL111SF_DEMOD_H__
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "mxl111sf.h"
|
||||
|
||||
struct mxl111sf_demod_config {
|
||||
int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data);
|
||||
int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data);
|
||||
int (*program_regs)(struct mxl111sf_state *state,
|
||||
struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DVB_USB_MXL111SF)
|
||||
extern
|
||||
struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
|
||||
struct mxl111sf_demod_config *cfg);
|
||||
#else
|
||||
static inline
|
||||
struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
|
||||
struct mxl111sf_demod_config *cfg)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_USB_MXL111SF */
|
||||
|
||||
#endif /* __MXL111SF_DEMOD_H__ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
763
drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
Normal file
763
drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
Normal file
|
|
@ -0,0 +1,763 @@
|
|||
/*
|
||||
* mxl111sf-gpio.c - driver for the MaxLinear MXL111SF
|
||||
*
|
||||
* Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* 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 "mxl111sf-gpio.h"
|
||||
#include "mxl111sf-i2c.h"
|
||||
#include "mxl111sf.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define MXL_GPIO_MUX_REG_0 0x84
|
||||
#define MXL_GPIO_MUX_REG_1 0x89
|
||||
#define MXL_GPIO_MUX_REG_2 0x82
|
||||
|
||||
#define MXL_GPIO_DIR_INPUT 0
|
||||
#define MXL_GPIO_DIR_OUTPUT 1
|
||||
|
||||
|
||||
static int mxl111sf_set_gpo_state(struct mxl111sf_state *state, u8 pin, u8 val)
|
||||
{
|
||||
int ret;
|
||||
u8 tmp;
|
||||
|
||||
mxl_debug_adv("(%d, %d)", pin, val);
|
||||
|
||||
if ((pin > 0) && (pin < 8)) {
|
||||
ret = mxl111sf_read_reg(state, 0x19, &tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
tmp &= ~(1 << (pin - 1));
|
||||
tmp |= (val << (pin - 1));
|
||||
ret = mxl111sf_write_reg(state, 0x19, tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
} else if (pin <= 10) {
|
||||
if (pin == 0)
|
||||
pin += 7;
|
||||
ret = mxl111sf_read_reg(state, 0x30, &tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
tmp &= ~(1 << (pin - 3));
|
||||
tmp |= (val << (pin - 3));
|
||||
ret = mxl111sf_write_reg(state, 0x30, tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
} else
|
||||
ret = -EINVAL;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_get_gpi_state(struct mxl111sf_state *state, u8 pin, u8 *val)
|
||||
{
|
||||
int ret;
|
||||
u8 tmp;
|
||||
|
||||
mxl_debug("(0x%02x)", pin);
|
||||
|
||||
*val = 0;
|
||||
|
||||
switch (pin) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
ret = mxl111sf_read_reg(state, 0x23, &tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
*val = (tmp >> (pin + 4)) & 0x01;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
ret = mxl111sf_read_reg(state, 0x2f, &tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
*val = (tmp >> pin) & 0x01;
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
ret = mxl111sf_read_reg(state, 0x22, &tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
*val = (tmp >> (pin - 3)) & 0x01;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL; /* invalid pin */
|
||||
}
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct mxl_gpio_cfg {
|
||||
u8 pin;
|
||||
u8 dir;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
static int mxl111sf_config_gpio_pins(struct mxl111sf_state *state,
|
||||
struct mxl_gpio_cfg *gpio_cfg)
|
||||
{
|
||||
int ret;
|
||||
u8 tmp;
|
||||
|
||||
mxl_debug_adv("(%d, %d)", gpio_cfg->pin, gpio_cfg->dir);
|
||||
|
||||
switch (gpio_cfg->pin) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_0, &tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
tmp &= ~(1 << (gpio_cfg->pin + 4));
|
||||
tmp |= (gpio_cfg->dir << (gpio_cfg->pin + 4));
|
||||
ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_0, tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_1, &tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
tmp &= ~(1 << gpio_cfg->pin);
|
||||
tmp |= (gpio_cfg->dir << gpio_cfg->pin);
|
||||
ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_1, tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_2, &tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
tmp &= ~(1 << (gpio_cfg->pin - 3));
|
||||
tmp |= (gpio_cfg->dir << (gpio_cfg->pin - 3));
|
||||
ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_2, tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL; /* invalid pin */
|
||||
}
|
||||
|
||||
ret = (MXL_GPIO_DIR_OUTPUT == gpio_cfg->dir) ?
|
||||
mxl111sf_set_gpo_state(state,
|
||||
gpio_cfg->pin, gpio_cfg->val) :
|
||||
mxl111sf_get_gpi_state(state,
|
||||
gpio_cfg->pin, &gpio_cfg->val);
|
||||
mxl_fail(ret);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_hw_do_set_gpio(struct mxl111sf_state *state,
|
||||
int gpio, int direction, int val)
|
||||
{
|
||||
struct mxl_gpio_cfg gpio_config = {
|
||||
.pin = gpio,
|
||||
.dir = direction,
|
||||
.val = val,
|
||||
};
|
||||
|
||||
mxl_debug("(%d, %d, %d)", gpio, direction, val);
|
||||
|
||||
return mxl111sf_config_gpio_pins(state, &gpio_config);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define PIN_MUX_MPEG_MODE_MASK 0x40 /* 0x17 <6> */
|
||||
#define PIN_MUX_MPEG_PAR_EN_MASK 0x01 /* 0x18 <0> */
|
||||
#define PIN_MUX_MPEG_SER_EN_MASK 0x02 /* 0x18 <1> */
|
||||
#define PIN_MUX_MPG_IN_MUX_MASK 0x80 /* 0x3D <7> */
|
||||
#define PIN_MUX_BT656_ENABLE_MASK 0x04 /* 0x12 <2> */
|
||||
#define PIN_MUX_I2S_ENABLE_MASK 0x40 /* 0x15 <6> */
|
||||
#define PIN_MUX_SPI_MODE_MASK 0x10 /* 0x3D <4> */
|
||||
#define PIN_MUX_MCLK_EN_CTRL_MASK 0x10 /* 0x82 <4> */
|
||||
#define PIN_MUX_MPSYN_EN_CTRL_MASK 0x20 /* 0x82 <5> */
|
||||
#define PIN_MUX_MDVAL_EN_CTRL_MASK 0x40 /* 0x82 <6> */
|
||||
#define PIN_MUX_MPERR_EN_CTRL_MASK 0x80 /* 0x82 <7> */
|
||||
#define PIN_MUX_MDAT_EN_0_MASK 0x10 /* 0x84 <4> */
|
||||
#define PIN_MUX_MDAT_EN_1_MASK 0x20 /* 0x84 <5> */
|
||||
#define PIN_MUX_MDAT_EN_2_MASK 0x40 /* 0x84 <6> */
|
||||
#define PIN_MUX_MDAT_EN_3_MASK 0x80 /* 0x84 <7> */
|
||||
#define PIN_MUX_MDAT_EN_4_MASK 0x10 /* 0x89 <4> */
|
||||
#define PIN_MUX_MDAT_EN_5_MASK 0x20 /* 0x89 <5> */
|
||||
#define PIN_MUX_MDAT_EN_6_MASK 0x40 /* 0x89 <6> */
|
||||
#define PIN_MUX_MDAT_EN_7_MASK 0x80 /* 0x89 <7> */
|
||||
|
||||
int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state,
|
||||
enum mxl111sf_mux_config pin_mux_config)
|
||||
{
|
||||
u8 r12, r15, r17, r18, r3D, r82, r84, r89;
|
||||
int ret;
|
||||
|
||||
mxl_debug("(%d)", pin_mux_config);
|
||||
|
||||
ret = mxl111sf_read_reg(state, 0x17, &r17);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_read_reg(state, 0x18, &r18);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_read_reg(state, 0x12, &r12);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_read_reg(state, 0x15, &r15);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_read_reg(state, 0x82, &r82);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_read_reg(state, 0x84, &r84);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_read_reg(state, 0x89, &r89);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_read_reg(state, 0x3D, &r3D);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
switch (pin_mux_config) {
|
||||
case PIN_MUX_TS_OUT_PARALLEL:
|
||||
/* mpeg_mode = 1 */
|
||||
r17 |= PIN_MUX_MPEG_MODE_MASK;
|
||||
/* mpeg_par_en = 1 */
|
||||
r18 |= PIN_MUX_MPEG_PAR_EN_MASK;
|
||||
/* mpeg_ser_en = 0 */
|
||||
r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
|
||||
/* mpg_in_mux = 0 */
|
||||
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
|
||||
/* bt656_enable = 0 */
|
||||
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
|
||||
/* i2s_enable = 0 */
|
||||
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
|
||||
/* spi_mode = 0 */
|
||||
r3D &= ~PIN_MUX_SPI_MODE_MASK;
|
||||
/* mclk_en_ctrl = 1 */
|
||||
r82 |= PIN_MUX_MCLK_EN_CTRL_MASK;
|
||||
/* mperr_en_ctrl = 1 */
|
||||
r82 |= PIN_MUX_MPERR_EN_CTRL_MASK;
|
||||
/* mdval_en_ctrl = 1 */
|
||||
r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK;
|
||||
/* mpsyn_en_ctrl = 1 */
|
||||
r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK;
|
||||
/* mdat_en_ctrl[3:0] = 0xF */
|
||||
r84 |= 0xF0;
|
||||
/* mdat_en_ctrl[7:4] = 0xF */
|
||||
r89 |= 0xF0;
|
||||
break;
|
||||
case PIN_MUX_TS_OUT_SERIAL:
|
||||
/* mpeg_mode = 1 */
|
||||
r17 |= PIN_MUX_MPEG_MODE_MASK;
|
||||
/* mpeg_par_en = 0 */
|
||||
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
|
||||
/* mpeg_ser_en = 1 */
|
||||
r18 |= PIN_MUX_MPEG_SER_EN_MASK;
|
||||
/* mpg_in_mux = 0 */
|
||||
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
|
||||
/* bt656_enable = 0 */
|
||||
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
|
||||
/* i2s_enable = 0 */
|
||||
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
|
||||
/* spi_mode = 0 */
|
||||
r3D &= ~PIN_MUX_SPI_MODE_MASK;
|
||||
/* mclk_en_ctrl = 1 */
|
||||
r82 |= PIN_MUX_MCLK_EN_CTRL_MASK;
|
||||
/* mperr_en_ctrl = 1 */
|
||||
r82 |= PIN_MUX_MPERR_EN_CTRL_MASK;
|
||||
/* mdval_en_ctrl = 1 */
|
||||
r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK;
|
||||
/* mpsyn_en_ctrl = 1 */
|
||||
r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK;
|
||||
/* mdat_en_ctrl[3:0] = 0xF */
|
||||
r84 |= 0xF0;
|
||||
/* mdat_en_ctrl[7:4] = 0xF */
|
||||
r89 |= 0xF0;
|
||||
break;
|
||||
case PIN_MUX_GPIO_MODE:
|
||||
/* mpeg_mode = 0 */
|
||||
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
|
||||
/* mpeg_par_en = 0 */
|
||||
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
|
||||
/* mpeg_ser_en = 0 */
|
||||
r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
|
||||
/* mpg_in_mux = 0 */
|
||||
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
|
||||
/* bt656_enable = 0 */
|
||||
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
|
||||
/* i2s_enable = 0 */
|
||||
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
|
||||
/* spi_mode = 0 */
|
||||
r3D &= ~PIN_MUX_SPI_MODE_MASK;
|
||||
/* mclk_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
|
||||
/* mperr_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
|
||||
/* mdval_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
|
||||
/* mpsyn_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
|
||||
/* mdat_en_ctrl[3:0] = 0x0 */
|
||||
r84 &= 0x0F;
|
||||
/* mdat_en_ctrl[7:4] = 0x0 */
|
||||
r89 &= 0x0F;
|
||||
break;
|
||||
case PIN_MUX_TS_SERIAL_IN_MODE_0:
|
||||
/* mpeg_mode = 0 */
|
||||
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
|
||||
/* mpeg_par_en = 0 */
|
||||
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
|
||||
/* mpeg_ser_en = 1 */
|
||||
r18 |= PIN_MUX_MPEG_SER_EN_MASK;
|
||||
/* mpg_in_mux = 0 */
|
||||
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
|
||||
/* bt656_enable = 0 */
|
||||
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
|
||||
/* i2s_enable = 0 */
|
||||
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
|
||||
/* spi_mode = 0 */
|
||||
r3D &= ~PIN_MUX_SPI_MODE_MASK;
|
||||
/* mclk_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
|
||||
/* mperr_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
|
||||
/* mdval_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
|
||||
/* mpsyn_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
|
||||
/* mdat_en_ctrl[3:0] = 0x0 */
|
||||
r84 &= 0x0F;
|
||||
/* mdat_en_ctrl[7:4] = 0x0 */
|
||||
r89 &= 0x0F;
|
||||
break;
|
||||
case PIN_MUX_TS_SERIAL_IN_MODE_1:
|
||||
/* mpeg_mode = 0 */
|
||||
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
|
||||
/* mpeg_par_en = 0 */
|
||||
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
|
||||
/* mpeg_ser_en = 1 */
|
||||
r18 |= PIN_MUX_MPEG_SER_EN_MASK;
|
||||
/* mpg_in_mux = 1 */
|
||||
r3D |= PIN_MUX_MPG_IN_MUX_MASK;
|
||||
/* bt656_enable = 0 */
|
||||
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
|
||||
/* i2s_enable = 0 */
|
||||
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
|
||||
/* spi_mode = 0 */
|
||||
r3D &= ~PIN_MUX_SPI_MODE_MASK;
|
||||
/* mclk_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
|
||||
/* mperr_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
|
||||
/* mdval_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
|
||||
/* mpsyn_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
|
||||
/* mdat_en_ctrl[3:0] = 0x0 */
|
||||
r84 &= 0x0F;
|
||||
/* mdat_en_ctrl[7:4] = 0x0 */
|
||||
r89 &= 0x0F;
|
||||
break;
|
||||
case PIN_MUX_TS_SPI_IN_MODE_1:
|
||||
/* mpeg_mode = 0 */
|
||||
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
|
||||
/* mpeg_par_en = 0 */
|
||||
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
|
||||
/* mpeg_ser_en = 1 */
|
||||
r18 |= PIN_MUX_MPEG_SER_EN_MASK;
|
||||
/* mpg_in_mux = 1 */
|
||||
r3D |= PIN_MUX_MPG_IN_MUX_MASK;
|
||||
/* bt656_enable = 0 */
|
||||
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
|
||||
/* i2s_enable = 1 */
|
||||
r15 |= PIN_MUX_I2S_ENABLE_MASK;
|
||||
/* spi_mode = 1 */
|
||||
r3D |= PIN_MUX_SPI_MODE_MASK;
|
||||
/* mclk_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
|
||||
/* mperr_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
|
||||
/* mdval_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
|
||||
/* mpsyn_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
|
||||
/* mdat_en_ctrl[3:0] = 0x0 */
|
||||
r84 &= 0x0F;
|
||||
/* mdat_en_ctrl[7:4] = 0x0 */
|
||||
r89 &= 0x0F;
|
||||
break;
|
||||
case PIN_MUX_TS_SPI_IN_MODE_0:
|
||||
/* mpeg_mode = 0 */
|
||||
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
|
||||
/* mpeg_par_en = 0 */
|
||||
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
|
||||
/* mpeg_ser_en = 1 */
|
||||
r18 |= PIN_MUX_MPEG_SER_EN_MASK;
|
||||
/* mpg_in_mux = 0 */
|
||||
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
|
||||
/* bt656_enable = 0 */
|
||||
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
|
||||
/* i2s_enable = 1 */
|
||||
r15 |= PIN_MUX_I2S_ENABLE_MASK;
|
||||
/* spi_mode = 1 */
|
||||
r3D |= PIN_MUX_SPI_MODE_MASK;
|
||||
/* mclk_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
|
||||
/* mperr_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
|
||||
/* mdval_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
|
||||
/* mpsyn_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
|
||||
/* mdat_en_ctrl[3:0] = 0x0 */
|
||||
r84 &= 0x0F;
|
||||
/* mdat_en_ctrl[7:4] = 0x0 */
|
||||
r89 &= 0x0F;
|
||||
break;
|
||||
case PIN_MUX_TS_PARALLEL_IN:
|
||||
/* mpeg_mode = 0 */
|
||||
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
|
||||
/* mpeg_par_en = 1 */
|
||||
r18 |= PIN_MUX_MPEG_PAR_EN_MASK;
|
||||
/* mpeg_ser_en = 0 */
|
||||
r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
|
||||
/* mpg_in_mux = 0 */
|
||||
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
|
||||
/* bt656_enable = 0 */
|
||||
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
|
||||
/* i2s_enable = 0 */
|
||||
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
|
||||
/* spi_mode = 0 */
|
||||
r3D &= ~PIN_MUX_SPI_MODE_MASK;
|
||||
/* mclk_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
|
||||
/* mperr_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
|
||||
/* mdval_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
|
||||
/* mpsyn_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
|
||||
/* mdat_en_ctrl[3:0] = 0x0 */
|
||||
r84 &= 0x0F;
|
||||
/* mdat_en_ctrl[7:4] = 0x0 */
|
||||
r89 &= 0x0F;
|
||||
break;
|
||||
case PIN_MUX_BT656_I2S_MODE:
|
||||
/* mpeg_mode = 0 */
|
||||
r17 &= ~PIN_MUX_MPEG_MODE_MASK;
|
||||
/* mpeg_par_en = 0 */
|
||||
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
|
||||
/* mpeg_ser_en = 0 */
|
||||
r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
|
||||
/* mpg_in_mux = 0 */
|
||||
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
|
||||
/* bt656_enable = 1 */
|
||||
r12 |= PIN_MUX_BT656_ENABLE_MASK;
|
||||
/* i2s_enable = 1 */
|
||||
r15 |= PIN_MUX_I2S_ENABLE_MASK;
|
||||
/* spi_mode = 0 */
|
||||
r3D &= ~PIN_MUX_SPI_MODE_MASK;
|
||||
/* mclk_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
|
||||
/* mperr_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
|
||||
/* mdval_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
|
||||
/* mpsyn_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
|
||||
/* mdat_en_ctrl[3:0] = 0x0 */
|
||||
r84 &= 0x0F;
|
||||
/* mdat_en_ctrl[7:4] = 0x0 */
|
||||
r89 &= 0x0F;
|
||||
break;
|
||||
case PIN_MUX_DEFAULT:
|
||||
default:
|
||||
/* mpeg_mode = 1 */
|
||||
r17 |= PIN_MUX_MPEG_MODE_MASK;
|
||||
/* mpeg_par_en = 0 */
|
||||
r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
|
||||
/* mpeg_ser_en = 0 */
|
||||
r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
|
||||
/* mpg_in_mux = 0 */
|
||||
r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
|
||||
/* bt656_enable = 0 */
|
||||
r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
|
||||
/* i2s_enable = 0 */
|
||||
r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
|
||||
/* spi_mode = 0 */
|
||||
r3D &= ~PIN_MUX_SPI_MODE_MASK;
|
||||
/* mclk_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
|
||||
/* mperr_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
|
||||
/* mdval_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
|
||||
/* mpsyn_en_ctrl = 0 */
|
||||
r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
|
||||
/* mdat_en_ctrl[3:0] = 0x0 */
|
||||
r84 &= 0x0F;
|
||||
/* mdat_en_ctrl[7:4] = 0x0 */
|
||||
r89 &= 0x0F;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = mxl111sf_write_reg(state, 0x17, r17);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_write_reg(state, 0x18, r18);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_write_reg(state, 0x12, r12);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_write_reg(state, 0x15, r15);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_write_reg(state, 0x82, r82);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_write_reg(state, 0x84, r84);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_write_reg(state, 0x89, r89);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_write_reg(state, 0x3D, r3D);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int mxl111sf_hw_set_gpio(struct mxl111sf_state *state, int gpio, int val)
|
||||
{
|
||||
return mxl111sf_hw_do_set_gpio(state, gpio, MXL_GPIO_DIR_OUTPUT, val);
|
||||
}
|
||||
|
||||
static int mxl111sf_hw_gpio_initialize(struct mxl111sf_state *state)
|
||||
{
|
||||
u8 gpioval = 0x07; /* write protect enabled, signal LEDs off */
|
||||
int i, ret;
|
||||
|
||||
mxl_debug("()");
|
||||
|
||||
for (i = 3; i < 8; i++) {
|
||||
ret = mxl111sf_hw_set_gpio(state, i, (gpioval >> i) & 0x01);
|
||||
if (mxl_fail(ret))
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define PCA9534_I2C_ADDR (0x40 >> 1)
|
||||
static int pca9534_set_gpio(struct mxl111sf_state *state, int gpio, int val)
|
||||
{
|
||||
u8 w[2] = { 1, 0 };
|
||||
u8 r = 0;
|
||||
struct i2c_msg msg[] = {
|
||||
{ .addr = PCA9534_I2C_ADDR,
|
||||
.flags = 0, .buf = w, .len = 1 },
|
||||
{ .addr = PCA9534_I2C_ADDR,
|
||||
.flags = I2C_M_RD, .buf = &r, .len = 1 },
|
||||
};
|
||||
|
||||
mxl_debug("(%d, %d)", gpio, val);
|
||||
|
||||
/* read current GPIO levels from flip-flop */
|
||||
i2c_transfer(&state->d->i2c_adap, msg, 2);
|
||||
|
||||
/* prepare write buffer with current GPIO levels */
|
||||
msg[0].len = 2;
|
||||
#if 0
|
||||
w[0] = 1;
|
||||
#endif
|
||||
w[1] = r;
|
||||
|
||||
/* clear the desired GPIO */
|
||||
w[1] &= ~(1 << gpio);
|
||||
|
||||
/* set the desired GPIO value */
|
||||
w[1] |= ((val ? 1 : 0) << gpio);
|
||||
|
||||
/* write new GPIO levels to flip-flop */
|
||||
i2c_transfer(&state->d->i2c_adap, &msg[0], 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pca9534_init_port_expander(struct mxl111sf_state *state)
|
||||
{
|
||||
u8 w[2] = { 1, 0x07 }; /* write protect enabled, signal LEDs off */
|
||||
|
||||
struct i2c_msg msg = {
|
||||
.addr = PCA9534_I2C_ADDR,
|
||||
.flags = 0, .buf = w, .len = 2
|
||||
};
|
||||
|
||||
mxl_debug("()");
|
||||
|
||||
i2c_transfer(&state->d->i2c_adap, &msg, 1);
|
||||
|
||||
/* configure all pins as outputs */
|
||||
w[0] = 3;
|
||||
w[1] = 0;
|
||||
|
||||
i2c_transfer(&state->d->i2c_adap, &msg, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val)
|
||||
{
|
||||
mxl_debug("(%d, %d)", gpio, val);
|
||||
|
||||
switch (state->gpio_port_expander) {
|
||||
default:
|
||||
mxl_printk(KERN_ERR,
|
||||
"gpio_port_expander undefined, assuming PCA9534");
|
||||
/* fall-thru */
|
||||
case mxl111sf_PCA9534:
|
||||
return pca9534_set_gpio(state, gpio, val);
|
||||
case mxl111sf_gpio_hw:
|
||||
return mxl111sf_hw_set_gpio(state, gpio, val);
|
||||
}
|
||||
}
|
||||
|
||||
static int mxl111sf_probe_port_expander(struct mxl111sf_state *state)
|
||||
{
|
||||
int ret;
|
||||
u8 w = 1;
|
||||
u8 r = 0;
|
||||
struct i2c_msg msg[] = {
|
||||
{ .flags = 0, .buf = &w, .len = 1 },
|
||||
{ .flags = I2C_M_RD, .buf = &r, .len = 1 },
|
||||
};
|
||||
|
||||
mxl_debug("()");
|
||||
|
||||
msg[0].addr = 0x70 >> 1;
|
||||
msg[1].addr = 0x70 >> 1;
|
||||
|
||||
/* read current GPIO levels from flip-flop */
|
||||
ret = i2c_transfer(&state->d->i2c_adap, msg, 2);
|
||||
if (ret == 2) {
|
||||
state->port_expander_addr = msg[0].addr;
|
||||
state->gpio_port_expander = mxl111sf_PCA9534;
|
||||
mxl_debug("found port expander at 0x%02x",
|
||||
state->port_expander_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
msg[0].addr = 0x40 >> 1;
|
||||
msg[1].addr = 0x40 >> 1;
|
||||
|
||||
ret = i2c_transfer(&state->d->i2c_adap, msg, 2);
|
||||
if (ret == 2) {
|
||||
state->port_expander_addr = msg[0].addr;
|
||||
state->gpio_port_expander = mxl111sf_PCA9534;
|
||||
mxl_debug("found port expander at 0x%02x",
|
||||
state->port_expander_addr);
|
||||
return 0;
|
||||
}
|
||||
state->port_expander_addr = 0xff;
|
||||
state->gpio_port_expander = mxl111sf_gpio_hw;
|
||||
mxl_debug("using hardware gpio");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mxl111sf_init_port_expander(struct mxl111sf_state *state)
|
||||
{
|
||||
mxl_debug("()");
|
||||
|
||||
if (0x00 == state->port_expander_addr)
|
||||
mxl111sf_probe_port_expander(state);
|
||||
|
||||
switch (state->gpio_port_expander) {
|
||||
default:
|
||||
mxl_printk(KERN_ERR,
|
||||
"gpio_port_expander undefined, assuming PCA9534");
|
||||
/* fall-thru */
|
||||
case mxl111sf_PCA9534:
|
||||
return pca9534_init_port_expander(state);
|
||||
case mxl111sf_gpio_hw:
|
||||
return mxl111sf_hw_gpio_initialize(state);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode)
|
||||
{
|
||||
/* GPO:
|
||||
* 3 - ATSC/MH# | 1 = ATSC transport, 0 = MH transport | default 0
|
||||
* 4 - ATSC_RST## | 1 = ATSC enable, 0 = ATSC Reset | default 0
|
||||
* 5 - ATSC_EN | 1 = ATSC power enable, 0 = ATSC power off | default 0
|
||||
* 6 - MH_RESET# | 1 = MH enable, 0 = MH Reset | default 0
|
||||
* 7 - MH_EN | 1 = MH power enable, 0 = MH power off | default 0
|
||||
*/
|
||||
mxl_debug("(%d)", mode);
|
||||
|
||||
switch (mode) {
|
||||
case MXL111SF_GPIO_MOD_MH:
|
||||
mxl111sf_set_gpio(state, 4, 0);
|
||||
mxl111sf_set_gpio(state, 5, 0);
|
||||
msleep(50);
|
||||
mxl111sf_set_gpio(state, 7, 1);
|
||||
msleep(50);
|
||||
mxl111sf_set_gpio(state, 6, 1);
|
||||
msleep(50);
|
||||
|
||||
mxl111sf_set_gpio(state, 3, 0);
|
||||
break;
|
||||
case MXL111SF_GPIO_MOD_ATSC:
|
||||
mxl111sf_set_gpio(state, 6, 0);
|
||||
mxl111sf_set_gpio(state, 7, 0);
|
||||
msleep(50);
|
||||
mxl111sf_set_gpio(state, 5, 1);
|
||||
msleep(50);
|
||||
mxl111sf_set_gpio(state, 4, 1);
|
||||
msleep(50);
|
||||
mxl111sf_set_gpio(state, 3, 1);
|
||||
break;
|
||||
default: /* DVBT / STANDBY */
|
||||
mxl111sf_init_port_expander(state);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
56
drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h
Normal file
56
drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* mxl111sf-gpio.h - driver for the MaxLinear MXL111SF
|
||||
*
|
||||
* Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* 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 _DVB_USB_MXL111SF_GPIO_H_
|
||||
#define _DVB_USB_MXL111SF_GPIO_H_
|
||||
|
||||
#include "mxl111sf.h"
|
||||
|
||||
int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val);
|
||||
int mxl111sf_init_port_expander(struct mxl111sf_state *state);
|
||||
|
||||
#define MXL111SF_GPIO_MOD_DVBT 0
|
||||
#define MXL111SF_GPIO_MOD_MH 1
|
||||
#define MXL111SF_GPIO_MOD_ATSC 2
|
||||
int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode);
|
||||
|
||||
enum mxl111sf_mux_config {
|
||||
PIN_MUX_DEFAULT = 0,
|
||||
PIN_MUX_TS_OUT_PARALLEL,
|
||||
PIN_MUX_TS_OUT_SERIAL,
|
||||
PIN_MUX_GPIO_MODE,
|
||||
PIN_MUX_TS_SERIAL_IN_MODE_0,
|
||||
PIN_MUX_TS_SERIAL_IN_MODE_1,
|
||||
PIN_MUX_TS_SPI_IN_MODE_0,
|
||||
PIN_MUX_TS_SPI_IN_MODE_1,
|
||||
PIN_MUX_TS_PARALLEL_IN,
|
||||
PIN_MUX_BT656_I2S_MODE,
|
||||
};
|
||||
|
||||
int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state,
|
||||
enum mxl111sf_mux_config pin_mux_config);
|
||||
|
||||
#endif /* _DVB_USB_MXL111SF_GPIO_H_ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
850
drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
Normal file
850
drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
Normal file
|
|
@ -0,0 +1,850 @@
|
|||
/*
|
||||
* mxl111sf-i2c.c - driver for the MaxLinear MXL111SF
|
||||
*
|
||||
* Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* 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 "mxl111sf-i2c.h"
|
||||
#include "mxl111sf.h"
|
||||
|
||||
/* SW-I2C ----------------------------------------------------------------- */
|
||||
|
||||
#define SW_I2C_ADDR 0x1a
|
||||
#define SW_I2C_EN 0x02
|
||||
#define SW_SCL_OUT 0x04
|
||||
#define SW_SDA_OUT 0x08
|
||||
#define SW_SDA_IN 0x04
|
||||
|
||||
#define SW_I2C_BUSY_ADDR 0x2f
|
||||
#define SW_I2C_BUSY 0x02
|
||||
|
||||
static int mxl111sf_i2c_bitbang_sendbyte(struct mxl111sf_state *state,
|
||||
u8 byte)
|
||||
{
|
||||
int i, ret;
|
||||
u8 data = 0;
|
||||
|
||||
mxl_i2c("(0x%02x)", byte);
|
||||
|
||||
ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
|
||||
data = (byte & (0x80 >> i)) ? SW_SDA_OUT : 0;
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | data);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | data | SW_SCL_OUT);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | data);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* last bit was 0 so we need to release SDA */
|
||||
if (!(byte & 1)) {
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | SW_SDA_OUT);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* CLK high for ACK readback */
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
/* drop the CLK after getting ACK, SDA will go high right away */
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | SW_SDA_OUT);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
if (data & SW_SDA_IN)
|
||||
ret = -EIO;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_i2c_bitbang_recvbyte(struct mxl111sf_state *state,
|
||||
u8 *pbyte)
|
||||
{
|
||||
int i, ret;
|
||||
u8 byte = 0;
|
||||
u8 data = 0;
|
||||
|
||||
mxl_i2c("()");
|
||||
|
||||
*pbyte = 0;
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | SW_SDA_OUT);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN |
|
||||
SW_SCL_OUT | SW_SDA_OUT);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
if (data & SW_SDA_IN)
|
||||
byte |= (0x80 >> i);
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | SW_SDA_OUT);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
}
|
||||
*pbyte = byte;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_i2c_start(struct mxl111sf_state *state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mxl_i2c("()");
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | SW_SCL_OUT);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN); /* start */
|
||||
mxl_fail(ret);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_i2c_stop(struct mxl111sf_state *state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mxl_i2c("()");
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN); /* stop */
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | SW_SCL_OUT);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_SCL_OUT | SW_SDA_OUT);
|
||||
mxl_fail(ret);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_i2c_ack(struct mxl111sf_state *state)
|
||||
{
|
||||
int ret;
|
||||
u8 b = 0;
|
||||
|
||||
mxl_i2c("()");
|
||||
|
||||
ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &b);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
/* pull SDA low */
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | SW_SCL_OUT);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | SW_SDA_OUT);
|
||||
mxl_fail(ret);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_i2c_nack(struct mxl111sf_state *state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mxl_i2c("()");
|
||||
|
||||
/* SDA high to signal last byte read from slave */
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
|
||||
0x10 | SW_I2C_EN | SW_SDA_OUT);
|
||||
mxl_fail(ret);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static int mxl111sf_i2c_sw_xfer_msg(struct mxl111sf_state *state,
|
||||
struct i2c_msg *msg)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
mxl_i2c("()");
|
||||
|
||||
if (msg->flags & I2C_M_RD) {
|
||||
|
||||
ret = mxl111sf_i2c_start(state);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_i2c_bitbang_sendbyte(state,
|
||||
(msg->addr << 1) | 0x01);
|
||||
if (mxl_fail(ret)) {
|
||||
mxl111sf_i2c_stop(state);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < msg->len; i++) {
|
||||
ret = mxl111sf_i2c_bitbang_recvbyte(state,
|
||||
&msg->buf[i]);
|
||||
if (mxl_fail(ret)) {
|
||||
mxl111sf_i2c_stop(state);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (i < msg->len - 1)
|
||||
mxl111sf_i2c_ack(state);
|
||||
}
|
||||
|
||||
mxl111sf_i2c_nack(state);
|
||||
|
||||
ret = mxl111sf_i2c_stop(state);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
} else {
|
||||
|
||||
ret = mxl111sf_i2c_start(state);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_i2c_bitbang_sendbyte(state,
|
||||
(msg->addr << 1) & 0xfe);
|
||||
if (mxl_fail(ret)) {
|
||||
mxl111sf_i2c_stop(state);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < msg->len; i++) {
|
||||
ret = mxl111sf_i2c_bitbang_sendbyte(state,
|
||||
msg->buf[i]);
|
||||
if (mxl_fail(ret)) {
|
||||
mxl111sf_i2c_stop(state);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: we only want to do this on the last transaction */
|
||||
mxl111sf_i2c_stop(state);
|
||||
}
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* HW-I2C ----------------------------------------------------------------- */
|
||||
|
||||
#define USB_WRITE_I2C_CMD 0x99
|
||||
#define USB_READ_I2C_CMD 0xdd
|
||||
#define USB_END_I2C_CMD 0xfe
|
||||
|
||||
#define USB_WRITE_I2C_CMD_LEN 26
|
||||
#define USB_READ_I2C_CMD_LEN 24
|
||||
|
||||
#define I2C_MUX_REG 0x30
|
||||
#define I2C_CONTROL_REG 0x00
|
||||
#define I2C_SLAVE_ADDR_REG 0x08
|
||||
#define I2C_DATA_REG 0x0c
|
||||
#define I2C_INT_STATUS_REG 0x10
|
||||
|
||||
static int mxl111sf_i2c_send_data(struct mxl111sf_state *state,
|
||||
u8 index, u8 *wdata)
|
||||
{
|
||||
int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
|
||||
&wdata[1], 25, NULL, 0);
|
||||
mxl_fail(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_i2c_get_data(struct mxl111sf_state *state,
|
||||
u8 index, u8 *wdata, u8 *rdata)
|
||||
{
|
||||
int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
|
||||
&wdata[1], 25, rdata, 24);
|
||||
mxl_fail(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u8 mxl111sf_i2c_check_status(struct mxl111sf_state *state)
|
||||
{
|
||||
u8 status = 0;
|
||||
u8 buf[26];
|
||||
|
||||
mxl_i2c_adv("()");
|
||||
|
||||
buf[0] = USB_READ_I2C_CMD;
|
||||
buf[1] = 0x00;
|
||||
|
||||
buf[2] = I2C_INT_STATUS_REG;
|
||||
buf[3] = 0x00;
|
||||
buf[4] = 0x00;
|
||||
|
||||
buf[5] = USB_END_I2C_CMD;
|
||||
|
||||
mxl111sf_i2c_get_data(state, 0, buf, buf);
|
||||
|
||||
if (buf[1] & 0x04)
|
||||
status = 1;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static u8 mxl111sf_i2c_check_fifo(struct mxl111sf_state *state)
|
||||
{
|
||||
u8 status = 0;
|
||||
u8 buf[26];
|
||||
|
||||
mxl_i2c("()");
|
||||
|
||||
buf[0] = USB_READ_I2C_CMD;
|
||||
buf[1] = 0x00;
|
||||
|
||||
buf[2] = I2C_MUX_REG;
|
||||
buf[3] = 0x00;
|
||||
buf[4] = 0x00;
|
||||
|
||||
buf[5] = I2C_INT_STATUS_REG;
|
||||
buf[6] = 0x00;
|
||||
buf[7] = 0x00;
|
||||
buf[8] = USB_END_I2C_CMD;
|
||||
|
||||
mxl111sf_i2c_get_data(state, 0, buf, buf);
|
||||
|
||||
if (0x08 == (buf[1] & 0x08))
|
||||
status = 1;
|
||||
|
||||
if ((buf[5] & 0x02) == 0x02)
|
||||
mxl_i2c("(buf[5] & 0x02) == 0x02"); /* FIXME */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int mxl111sf_i2c_readagain(struct mxl111sf_state *state,
|
||||
u8 count, u8 *rbuf)
|
||||
{
|
||||
u8 i2c_w_data[26];
|
||||
u8 i2c_r_data[24];
|
||||
u8 i = 0;
|
||||
u8 fifo_status = 0;
|
||||
int status = 0;
|
||||
|
||||
mxl_i2c("read %d bytes", count);
|
||||
|
||||
while ((fifo_status == 0) && (i++ < 5))
|
||||
fifo_status = mxl111sf_i2c_check_fifo(state);
|
||||
|
||||
i2c_w_data[0] = 0xDD;
|
||||
i2c_w_data[1] = 0x00;
|
||||
|
||||
for (i = 2; i < 26; i++)
|
||||
i2c_w_data[i] = 0xFE;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
i2c_w_data[2+(i*3)] = 0x0C;
|
||||
i2c_w_data[3+(i*3)] = 0x00;
|
||||
i2c_w_data[4+(i*3)] = 0x00;
|
||||
}
|
||||
|
||||
mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data);
|
||||
|
||||
/* Check for I2C NACK status */
|
||||
if (mxl111sf_i2c_check_status(state) == 1) {
|
||||
mxl_i2c("error!");
|
||||
} else {
|
||||
for (i = 0; i < count; i++) {
|
||||
rbuf[i] = i2c_r_data[(i*3)+1];
|
||||
mxl_i2c("%02x\t %02x",
|
||||
i2c_r_data[(i*3)+1],
|
||||
i2c_r_data[(i*3)+2]);
|
||||
}
|
||||
|
||||
status = 1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#define HWI2C400 1
|
||||
static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state,
|
||||
struct i2c_msg *msg)
|
||||
{
|
||||
int i, k, ret = 0;
|
||||
u16 index = 0;
|
||||
u8 buf[26];
|
||||
u8 i2c_r_data[24];
|
||||
u16 block_len;
|
||||
u16 left_over_len;
|
||||
u8 rd_status[8];
|
||||
u8 ret_status;
|
||||
u8 readbuff[26];
|
||||
|
||||
mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d",
|
||||
msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0,
|
||||
(!(msg->flags & I2C_M_RD)) ? msg->len : 0);
|
||||
|
||||
for (index = 0; index < 26; index++)
|
||||
buf[index] = USB_END_I2C_CMD;
|
||||
|
||||
/* command to indicate data payload is destined for I2C interface */
|
||||
buf[0] = USB_WRITE_I2C_CMD;
|
||||
buf[1] = 0x00;
|
||||
|
||||
/* enable I2C interface */
|
||||
buf[2] = I2C_MUX_REG;
|
||||
buf[3] = 0x80;
|
||||
buf[4] = 0x00;
|
||||
|
||||
/* enable I2C interface */
|
||||
buf[5] = I2C_MUX_REG;
|
||||
buf[6] = 0x81;
|
||||
buf[7] = 0x00;
|
||||
|
||||
/* set Timeout register on I2C interface */
|
||||
buf[8] = 0x14;
|
||||
buf[9] = 0xff;
|
||||
buf[10] = 0x00;
|
||||
#if 0
|
||||
/* enable Interrupts on I2C interface */
|
||||
buf[8] = 0x24;
|
||||
buf[9] = 0xF7;
|
||||
buf[10] = 0x00;
|
||||
#endif
|
||||
buf[11] = 0x24;
|
||||
buf[12] = 0xF7;
|
||||
buf[13] = 0x00;
|
||||
|
||||
ret = mxl111sf_i2c_send_data(state, 0, buf);
|
||||
|
||||
/* write data on I2C bus */
|
||||
if (!(msg->flags & I2C_M_RD) && (msg->len > 0)) {
|
||||
mxl_i2c("%d\t%02x", msg->len, msg->buf[0]);
|
||||
|
||||
/* control register on I2C interface to initialize I2C bus */
|
||||
buf[2] = I2C_CONTROL_REG;
|
||||
buf[3] = 0x5E;
|
||||
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
|
||||
|
||||
/* I2C Slave device Address */
|
||||
buf[5] = I2C_SLAVE_ADDR_REG;
|
||||
buf[6] = (msg->addr);
|
||||
buf[7] = 0x00;
|
||||
buf[8] = USB_END_I2C_CMD;
|
||||
ret = mxl111sf_i2c_send_data(state, 0, buf);
|
||||
|
||||
/* check for slave device status */
|
||||
if (mxl111sf_i2c_check_status(state) == 1) {
|
||||
mxl_i2c("NACK writing slave address %02x",
|
||||
msg->addr);
|
||||
/* if NACK, stop I2C bus and exit */
|
||||
buf[2] = I2C_CONTROL_REG;
|
||||
buf[3] = 0x4E;
|
||||
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
|
||||
ret = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* I2C interface can do I2C operations in block of 8 bytes of
|
||||
I2C data. calculation to figure out number of blocks of i2c
|
||||
data required to program */
|
||||
block_len = (msg->len / 8);
|
||||
left_over_len = (msg->len % 8);
|
||||
index = 0;
|
||||
|
||||
mxl_i2c("block_len %d, left_over_len %d",
|
||||
block_len, left_over_len);
|
||||
|
||||
for (index = 0; index < block_len; index++) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
/* write data on I2C interface */
|
||||
buf[2+(i*3)] = I2C_DATA_REG;
|
||||
buf[3+(i*3)] = msg->buf[(index*8)+i];
|
||||
buf[4+(i*3)] = 0x00;
|
||||
}
|
||||
|
||||
ret = mxl111sf_i2c_send_data(state, 0, buf);
|
||||
|
||||
/* check for I2C NACK status */
|
||||
if (mxl111sf_i2c_check_status(state) == 1) {
|
||||
mxl_i2c("NACK writing slave address %02x",
|
||||
msg->addr);
|
||||
|
||||
/* if NACK, stop I2C bus and exit */
|
||||
buf[2] = I2C_CONTROL_REG;
|
||||
buf[3] = 0x4E;
|
||||
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
|
||||
ret = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (left_over_len) {
|
||||
for (k = 0; k < 26; k++)
|
||||
buf[k] = USB_END_I2C_CMD;
|
||||
|
||||
buf[0] = 0x99;
|
||||
buf[1] = 0x00;
|
||||
|
||||
for (i = 0; i < left_over_len; i++) {
|
||||
buf[2+(i*3)] = I2C_DATA_REG;
|
||||
buf[3+(i*3)] = msg->buf[(index*8)+i];
|
||||
mxl_i2c("index = %d %d data %d",
|
||||
index, i, msg->buf[(index*8)+i]);
|
||||
buf[4+(i*3)] = 0x00;
|
||||
}
|
||||
ret = mxl111sf_i2c_send_data(state, 0, buf);
|
||||
|
||||
/* check for I2C NACK status */
|
||||
if (mxl111sf_i2c_check_status(state) == 1) {
|
||||
mxl_i2c("NACK writing slave address %02x",
|
||||
msg->addr);
|
||||
|
||||
/* if NACK, stop I2C bus and exit */
|
||||
buf[2] = I2C_CONTROL_REG;
|
||||
buf[3] = 0x4E;
|
||||
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
|
||||
ret = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* issue I2C STOP after write */
|
||||
buf[2] = I2C_CONTROL_REG;
|
||||
buf[3] = 0x4E;
|
||||
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
|
||||
|
||||
}
|
||||
|
||||
/* read data from I2C bus */
|
||||
if ((msg->flags & I2C_M_RD) && (msg->len > 0)) {
|
||||
mxl_i2c("read buf len %d", msg->len);
|
||||
|
||||
/* command to indicate data payload is
|
||||
destined for I2C interface */
|
||||
buf[2] = I2C_CONTROL_REG;
|
||||
buf[3] = 0xDF;
|
||||
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
|
||||
|
||||
/* I2C xfer length */
|
||||
buf[5] = 0x14;
|
||||
buf[6] = (msg->len & 0xFF);
|
||||
buf[7] = 0;
|
||||
|
||||
/* I2C slave device Address */
|
||||
buf[8] = I2C_SLAVE_ADDR_REG;
|
||||
buf[9] = msg->addr;
|
||||
buf[10] = 0x00;
|
||||
buf[11] = USB_END_I2C_CMD;
|
||||
ret = mxl111sf_i2c_send_data(state, 0, buf);
|
||||
|
||||
/* check for I2C NACK status */
|
||||
if (mxl111sf_i2c_check_status(state) == 1) {
|
||||
mxl_i2c("NACK reading slave address %02x",
|
||||
msg->addr);
|
||||
|
||||
/* if NACK, stop I2C bus and exit */
|
||||
buf[2] = I2C_CONTROL_REG;
|
||||
buf[3] = 0xC7;
|
||||
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
|
||||
ret = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* I2C interface can do I2C operations in block of 8 bytes of
|
||||
I2C data. calculation to figure out number of blocks of
|
||||
i2c data required to program */
|
||||
block_len = ((msg->len) / 8);
|
||||
left_over_len = ((msg->len) % 8);
|
||||
index = 0;
|
||||
|
||||
mxl_i2c("block_len %d, left_over_len %d",
|
||||
block_len, left_over_len);
|
||||
|
||||
/* command to read data from I2C interface */
|
||||
buf[0] = USB_READ_I2C_CMD;
|
||||
buf[1] = 0x00;
|
||||
|
||||
for (index = 0; index < block_len; index++) {
|
||||
/* setup I2C read request packet on I2C interface */
|
||||
for (i = 0; i < 8; i++) {
|
||||
buf[2+(i*3)] = I2C_DATA_REG;
|
||||
buf[3+(i*3)] = 0x00;
|
||||
buf[4+(i*3)] = 0x00;
|
||||
}
|
||||
|
||||
ret = mxl111sf_i2c_get_data(state, 0, buf, i2c_r_data);
|
||||
|
||||
/* check for I2C NACK status */
|
||||
if (mxl111sf_i2c_check_status(state) == 1) {
|
||||
mxl_i2c("NACK reading slave address %02x",
|
||||
msg->addr);
|
||||
|
||||
/* if NACK, stop I2C bus and exit */
|
||||
buf[2] = I2C_CONTROL_REG;
|
||||
buf[3] = 0xC7;
|
||||
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
|
||||
ret = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* copy data from i2c data payload to read buffer */
|
||||
for (i = 0; i < 8; i++) {
|
||||
rd_status[i] = i2c_r_data[(i*3)+2];
|
||||
|
||||
if (rd_status[i] == 0x04) {
|
||||
if (i < 7) {
|
||||
mxl_i2c("i2c fifo empty!"
|
||||
" @ %d", i);
|
||||
msg->buf[(index*8)+i] =
|
||||
i2c_r_data[(i*3)+1];
|
||||
/* read again */
|
||||
ret_status =
|
||||
mxl111sf_i2c_readagain(
|
||||
state, 8-(i+1),
|
||||
readbuff);
|
||||
if (ret_status == 1) {
|
||||
for (k = 0;
|
||||
k < 8-(i+1);
|
||||
k++) {
|
||||
|
||||
msg->buf[(index*8)+(k+i+1)] =
|
||||
readbuff[k];
|
||||
mxl_i2c("read data: %02x\t %02x",
|
||||
msg->buf[(index*8)+(k+i)],
|
||||
(index*8)+(k+i));
|
||||
mxl_i2c("read data: %02x\t %02x",
|
||||
msg->buf[(index*8)+(k+i+1)],
|
||||
readbuff[k]);
|
||||
|
||||
}
|
||||
goto stop_copy;
|
||||
} else {
|
||||
mxl_i2c("readagain "
|
||||
"ERROR!");
|
||||
}
|
||||
} else {
|
||||
msg->buf[(index*8)+i] =
|
||||
i2c_r_data[(i*3)+1];
|
||||
}
|
||||
} else {
|
||||
msg->buf[(index*8)+i] =
|
||||
i2c_r_data[(i*3)+1];
|
||||
}
|
||||
}
|
||||
stop_copy:
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
if (left_over_len) {
|
||||
for (k = 0; k < 26; k++)
|
||||
buf[k] = USB_END_I2C_CMD;
|
||||
|
||||
buf[0] = 0xDD;
|
||||
buf[1] = 0x00;
|
||||
|
||||
for (i = 0; i < left_over_len; i++) {
|
||||
buf[2+(i*3)] = I2C_DATA_REG;
|
||||
buf[3+(i*3)] = 0x00;
|
||||
buf[4+(i*3)] = 0x00;
|
||||
}
|
||||
ret = mxl111sf_i2c_get_data(state, 0, buf,
|
||||
i2c_r_data);
|
||||
|
||||
/* check for I2C NACK status */
|
||||
if (mxl111sf_i2c_check_status(state) == 1) {
|
||||
mxl_i2c("NACK reading slave address %02x",
|
||||
msg->addr);
|
||||
|
||||
/* if NACK, stop I2C bus and exit */
|
||||
buf[2] = I2C_CONTROL_REG;
|
||||
buf[3] = 0xC7;
|
||||
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
|
||||
ret = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < left_over_len; i++) {
|
||||
msg->buf[(block_len*8)+i] =
|
||||
i2c_r_data[(i*3)+1];
|
||||
mxl_i2c("read data: %02x\t %02x",
|
||||
i2c_r_data[(i*3)+1],
|
||||
i2c_r_data[(i*3)+2]);
|
||||
}
|
||||
}
|
||||
|
||||
/* indicate I2C interface to issue NACK
|
||||
after next I2C read op */
|
||||
buf[0] = USB_WRITE_I2C_CMD;
|
||||
buf[1] = 0x00;
|
||||
|
||||
/* control register */
|
||||
buf[2] = I2C_CONTROL_REG;
|
||||
buf[3] = 0x17;
|
||||
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
|
||||
|
||||
buf[5] = USB_END_I2C_CMD;
|
||||
ret = mxl111sf_i2c_send_data(state, 0, buf);
|
||||
|
||||
/* control register */
|
||||
buf[2] = I2C_CONTROL_REG;
|
||||
buf[3] = 0xC7;
|
||||
buf[4] = (HWI2C400) ? 0x03 : 0x0D;
|
||||
|
||||
}
|
||||
exit:
|
||||
/* STOP and disable I2C MUX */
|
||||
buf[0] = USB_WRITE_I2C_CMD;
|
||||
buf[1] = 0x00;
|
||||
|
||||
/* de-initilize I2C BUS */
|
||||
buf[5] = USB_END_I2C_CMD;
|
||||
mxl111sf_i2c_send_data(state, 0, buf);
|
||||
|
||||
/* Control Register */
|
||||
buf[2] = I2C_CONTROL_REG;
|
||||
buf[3] = 0xDF;
|
||||
buf[4] = 0x03;
|
||||
|
||||
/* disable I2C interface */
|
||||
buf[5] = I2C_MUX_REG;
|
||||
buf[6] = 0x00;
|
||||
buf[7] = 0x00;
|
||||
|
||||
/* de-initilize I2C BUS */
|
||||
buf[8] = USB_END_I2C_CMD;
|
||||
mxl111sf_i2c_send_data(state, 0, buf);
|
||||
|
||||
/* disable I2C interface */
|
||||
buf[2] = I2C_MUX_REG;
|
||||
buf[3] = 0x81;
|
||||
buf[4] = 0x00;
|
||||
|
||||
/* disable I2C interface */
|
||||
buf[5] = I2C_MUX_REG;
|
||||
buf[6] = 0x00;
|
||||
buf[7] = 0x00;
|
||||
|
||||
/* disable I2C interface */
|
||||
buf[8] = I2C_MUX_REG;
|
||||
buf[9] = 0x00;
|
||||
buf[10] = 0x00;
|
||||
|
||||
buf[11] = USB_END_I2C_CMD;
|
||||
mxl111sf_i2c_send_data(state, 0, buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg msg[], int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
struct mxl111sf_state *state = d->priv;
|
||||
int hwi2c = (state->chip_rev > MXL111SF_V6);
|
||||
int i, ret;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
ret = (hwi2c) ?
|
||||
mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) :
|
||||
mxl111sf_i2c_sw_xfer_msg(state, &msg[i]);
|
||||
if (mxl_fail(ret)) {
|
||||
mxl_debug_adv("failed with error %d on i2c "
|
||||
"transaction %d of %d, %sing %d bytes "
|
||||
"to/from 0x%02x", ret, i+1, num,
|
||||
(msg[i].flags & I2C_M_RD) ?
|
||||
"read" : "writ",
|
||||
msg[i].len, msg[i].addr);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
|
||||
return i == num ? num : -EREMOTEIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
35
drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h
Normal file
35
drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* mxl111sf-i2c.h - driver for the MaxLinear MXL111SF
|
||||
*
|
||||
* Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* 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 _DVB_USB_MXL111SF_I2C_H_
|
||||
#define _DVB_USB_MXL111SF_I2C_H_
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
||||
int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg msg[], int num);
|
||||
|
||||
#endif /* _DVB_USB_MXL111SF_I2C_H_ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
343
drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c
Normal file
343
drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* mxl111sf-phy.c - driver for the MaxLinear MXL111SF
|
||||
*
|
||||
* Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* 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 "mxl111sf-phy.h"
|
||||
#include "mxl111sf-reg.h"
|
||||
|
||||
int mxl111sf_init_tuner_demod(struct mxl111sf_state *state)
|
||||
{
|
||||
struct mxl111sf_reg_ctrl_info mxl_111_overwrite_default[] = {
|
||||
{0x07, 0xff, 0x0c},
|
||||
{0x58, 0xff, 0x9d},
|
||||
{0x09, 0xff, 0x00},
|
||||
{0x06, 0xff, 0x06},
|
||||
{0xc8, 0xff, 0x40}, /* ED_LE_WIN_OLD = 0 */
|
||||
{0x8d, 0x01, 0x01}, /* NEGATE_Q */
|
||||
{0x32, 0xff, 0xac}, /* DIG_RFREFSELECT = 12 */
|
||||
{0x42, 0xff, 0x43}, /* DIG_REG_AMP = 4 */
|
||||
{0x74, 0xff, 0xc4}, /* SSPUR_FS_PRIO = 4 */
|
||||
{0x71, 0xff, 0xe6}, /* SPUR_ROT_PRIO_VAL = 1 */
|
||||
{0x83, 0xff, 0x64}, /* INF_FILT1_THD_SC = 100 */
|
||||
{0x85, 0xff, 0x64}, /* INF_FILT2_THD_SC = 100 */
|
||||
{0x88, 0xff, 0xf0}, /* INF_THD = 240 */
|
||||
{0x6f, 0xf0, 0xb0}, /* DFE_DLY = 11 */
|
||||
{0x00, 0xff, 0x01}, /* Change to page 1 */
|
||||
{0x81, 0xff, 0x11}, /* DSM_FERR_BYPASS = 1 */
|
||||
{0xf4, 0xff, 0x07}, /* DIG_FREQ_CORR = 1 */
|
||||
{0xd4, 0x1f, 0x0f}, /* SPUR_TEST_NOISE_TH = 15 */
|
||||
{0xd6, 0xff, 0x0c}, /* SPUR_TEST_NOISE_PAPR = 12 */
|
||||
{0x00, 0xff, 0x00}, /* Change to page 0 */
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
mxl_debug("()");
|
||||
|
||||
return mxl111sf_ctrl_program_regs(state, mxl_111_overwrite_default);
|
||||
}
|
||||
|
||||
int mxl1x1sf_soft_reset(struct mxl111sf_state *state)
|
||||
{
|
||||
int ret;
|
||||
mxl_debug("()");
|
||||
|
||||
ret = mxl111sf_write_reg(state, 0xff, 0x00); /* AIC */
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_write_reg(state, 0x02, 0x01); /* get out of reset */
|
||||
mxl_fail(ret);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mxl_debug("(%s)", MXL_SOC_MODE == mode ?
|
||||
"MXL_SOC_MODE" : "MXL_TUNER_MODE");
|
||||
|
||||
/* set device mode */
|
||||
ret = mxl111sf_write_reg(state, 0x03,
|
||||
MXL_SOC_MODE == mode ? 0x01 : 0x00);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_write_reg_mask(state,
|
||||
0x7d, 0x40, MXL_SOC_MODE == mode ?
|
||||
0x00 : /* enable impulse noise filter,
|
||||
INF_BYP = 0 */
|
||||
0x40); /* disable impulse noise filter,
|
||||
INF_BYP = 1 */
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
state->device_mode = mode;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power up tuner */
|
||||
int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff)
|
||||
{
|
||||
mxl_debug("(%d)", onoff);
|
||||
|
||||
return mxl111sf_write_reg(state, 0x01, onoff ? 0x01 : 0x00);
|
||||
}
|
||||
|
||||
int mxl111sf_disable_656_port(struct mxl111sf_state *state)
|
||||
{
|
||||
mxl_debug("()");
|
||||
|
||||
return mxl111sf_write_reg_mask(state, 0x12, 0x04, 0x00);
|
||||
}
|
||||
|
||||
int mxl111sf_enable_usb_output(struct mxl111sf_state *state)
|
||||
{
|
||||
mxl_debug("()");
|
||||
|
||||
return mxl111sf_write_reg_mask(state, 0x17, 0x40, 0x00);
|
||||
}
|
||||
|
||||
/* initialize TSIF as input port of MxL1X1SF for MPEG2 data transfer */
|
||||
int mxl111sf_config_mpeg_in(struct mxl111sf_state *state,
|
||||
unsigned int parallel_serial,
|
||||
unsigned int msb_lsb_1st,
|
||||
unsigned int clock_phase,
|
||||
unsigned int mpeg_valid_pol,
|
||||
unsigned int mpeg_sync_pol)
|
||||
{
|
||||
int ret;
|
||||
u8 mode, tmp;
|
||||
|
||||
mxl_debug("(%u,%u,%u,%u,%u)", parallel_serial, msb_lsb_1st,
|
||||
clock_phase, mpeg_valid_pol, mpeg_sync_pol);
|
||||
|
||||
/* Enable PIN MUX */
|
||||
ret = mxl111sf_write_reg(state, V6_PIN_MUX_MODE_REG, V6_ENABLE_PIN_MUX);
|
||||
mxl_fail(ret);
|
||||
|
||||
/* Configure MPEG Clock phase */
|
||||
mxl111sf_read_reg(state, V6_MPEG_IN_CLK_INV_REG, &mode);
|
||||
|
||||
if (clock_phase == TSIF_NORMAL)
|
||||
mode &= ~V6_INVERTED_CLK_PHASE;
|
||||
else
|
||||
mode |= V6_INVERTED_CLK_PHASE;
|
||||
|
||||
ret = mxl111sf_write_reg(state, V6_MPEG_IN_CLK_INV_REG, mode);
|
||||
mxl_fail(ret);
|
||||
|
||||
/* Configure data input mode, MPEG Valid polarity, MPEG Sync polarity
|
||||
* Get current configuration */
|
||||
ret = mxl111sf_read_reg(state, V6_MPEG_IN_CTRL_REG, &mode);
|
||||
mxl_fail(ret);
|
||||
|
||||
/* Data Input mode */
|
||||
if (parallel_serial == TSIF_INPUT_PARALLEL) {
|
||||
/* Disable serial mode */
|
||||
mode &= ~V6_MPEG_IN_DATA_SERIAL;
|
||||
|
||||
/* Enable Parallel mode */
|
||||
mode |= V6_MPEG_IN_DATA_PARALLEL;
|
||||
} else {
|
||||
/* Disable Parallel mode */
|
||||
mode &= ~V6_MPEG_IN_DATA_PARALLEL;
|
||||
|
||||
/* Enable Serial Mode */
|
||||
mode |= V6_MPEG_IN_DATA_SERIAL;
|
||||
|
||||
/* If serial interface is chosen, configure
|
||||
MSB or LSB order in transmission */
|
||||
ret = mxl111sf_read_reg(state,
|
||||
V6_MPEG_INOUT_BIT_ORDER_CTRL_REG,
|
||||
&tmp);
|
||||
mxl_fail(ret);
|
||||
|
||||
if (msb_lsb_1st == MPEG_SER_MSB_FIRST_ENABLED)
|
||||
tmp |= V6_MPEG_SER_MSB_FIRST;
|
||||
else
|
||||
tmp &= ~V6_MPEG_SER_MSB_FIRST;
|
||||
|
||||
ret = mxl111sf_write_reg(state,
|
||||
V6_MPEG_INOUT_BIT_ORDER_CTRL_REG,
|
||||
tmp);
|
||||
mxl_fail(ret);
|
||||
}
|
||||
|
||||
/* MPEG Sync polarity */
|
||||
if (mpeg_sync_pol == TSIF_NORMAL)
|
||||
mode &= ~V6_INVERTED_MPEG_SYNC;
|
||||
else
|
||||
mode |= V6_INVERTED_MPEG_SYNC;
|
||||
|
||||
/* MPEG Valid polarity */
|
||||
if (mpeg_valid_pol == 0)
|
||||
mode &= ~V6_INVERTED_MPEG_VALID;
|
||||
else
|
||||
mode |= V6_INVERTED_MPEG_VALID;
|
||||
|
||||
ret = mxl111sf_write_reg(state, V6_MPEG_IN_CTRL_REG, mode);
|
||||
mxl_fail(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size)
|
||||
{
|
||||
static struct mxl111sf_reg_ctrl_info init_i2s[] = {
|
||||
{0x1b, 0xff, 0x1e}, /* pin mux mode, Choose 656/I2S input */
|
||||
{0x15, 0x60, 0x60}, /* Enable I2S */
|
||||
{0x17, 0xe0, 0x20}, /* Input, MPEG MODE USB,
|
||||
Inverted 656 Clock, I2S_SOFT_RESET,
|
||||
0 : Normal operation, 1 : Reset State */
|
||||
#if 0
|
||||
{0x12, 0x01, 0x00}, /* AUDIO_IRQ_CLR (Overflow Indicator) */
|
||||
#endif
|
||||
{0x00, 0xff, 0x02}, /* Change to Control Page */
|
||||
{0x26, 0x0d, 0x0d}, /* I2S_MODE & BT656_SRC_SEL for FPGA only */
|
||||
{0x00, 0xff, 0x00},
|
||||
{0, 0, 0}
|
||||
};
|
||||
int ret;
|
||||
|
||||
mxl_debug("(0x%02x)", sample_size);
|
||||
|
||||
ret = mxl111sf_ctrl_program_regs(state, init_i2s);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_write_reg(state, V6_I2S_NUM_SAMPLES_REG, sample_size);
|
||||
mxl_fail(ret);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mxl111sf_disable_i2s_port(struct mxl111sf_state *state)
|
||||
{
|
||||
static struct mxl111sf_reg_ctrl_info disable_i2s[] = {
|
||||
{0x15, 0x40, 0x00},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
mxl_debug("()");
|
||||
|
||||
return mxl111sf_ctrl_program_regs(state, disable_i2s);
|
||||
}
|
||||
|
||||
int mxl111sf_config_i2s(struct mxl111sf_state *state,
|
||||
u8 msb_start_pos, u8 data_width)
|
||||
{
|
||||
int ret;
|
||||
u8 tmp;
|
||||
|
||||
mxl_debug("(0x%02x, 0x%02x)", msb_start_pos, data_width);
|
||||
|
||||
ret = mxl111sf_read_reg(state, V6_I2S_STREAM_START_BIT_REG, &tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
tmp &= 0xe0;
|
||||
tmp |= msb_start_pos;
|
||||
ret = mxl111sf_write_reg(state, V6_I2S_STREAM_START_BIT_REG, tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_read_reg(state, V6_I2S_STREAM_END_BIT_REG, &tmp);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
tmp &= 0xe0;
|
||||
tmp |= data_width;
|
||||
ret = mxl111sf_write_reg(state, V6_I2S_STREAM_END_BIT_REG, tmp);
|
||||
mxl_fail(ret);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff)
|
||||
{
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
mxl_debug("(%d)", onoff);
|
||||
|
||||
ret = mxl111sf_write_reg(state, 0x00, 0x02);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_read_reg(state, V8_SPI_MODE_REG, &val);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
if (onoff)
|
||||
val |= 0x04;
|
||||
else
|
||||
val &= ~0x04;
|
||||
|
||||
ret = mxl111sf_write_reg(state, V8_SPI_MODE_REG, val);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ret = mxl111sf_write_reg(state, 0x00, 0x00);
|
||||
mxl_fail(ret);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mxl111sf_idac_config(struct mxl111sf_state *state,
|
||||
u8 control_mode, u8 current_setting,
|
||||
u8 current_value, u8 hysteresis_value)
|
||||
{
|
||||
int ret;
|
||||
u8 val;
|
||||
/* current value will be set for both automatic & manual IDAC control */
|
||||
val = current_value;
|
||||
|
||||
if (control_mode == IDAC_MANUAL_CONTROL) {
|
||||
/* enable manual control of IDAC */
|
||||
val |= IDAC_MANUAL_CONTROL_BIT_MASK;
|
||||
|
||||
if (current_setting == IDAC_CURRENT_SINKING_ENABLE)
|
||||
/* enable current sinking in manual mode */
|
||||
val |= IDAC_CURRENT_SINKING_BIT_MASK;
|
||||
else
|
||||
/* disable current sinking in manual mode */
|
||||
val &= ~IDAC_CURRENT_SINKING_BIT_MASK;
|
||||
} else {
|
||||
/* disable manual control of IDAC */
|
||||
val &= ~IDAC_MANUAL_CONTROL_BIT_MASK;
|
||||
|
||||
/* set hysteresis value reg: 0x0B<5:0> */
|
||||
ret = mxl111sf_write_reg(state, V6_IDAC_HYSTERESIS_REG,
|
||||
(hysteresis_value & 0x3F));
|
||||
mxl_fail(ret);
|
||||
}
|
||||
|
||||
ret = mxl111sf_write_reg(state, V6_IDAC_SETTINGS_REG, val);
|
||||
mxl_fail(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
53
drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h
Normal file
53
drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* mxl111sf-phy.h - driver for the MaxLinear MXL111SF
|
||||
*
|
||||
* Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* 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 _DVB_USB_MXL111SF_PHY_H_
|
||||
#define _DVB_USB_MXL111SF_PHY_H_
|
||||
|
||||
#include "mxl111sf.h"
|
||||
|
||||
int mxl1x1sf_soft_reset(struct mxl111sf_state *state);
|
||||
int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode);
|
||||
int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff);
|
||||
int mxl111sf_disable_656_port(struct mxl111sf_state *state);
|
||||
int mxl111sf_init_tuner_demod(struct mxl111sf_state *state);
|
||||
int mxl111sf_enable_usb_output(struct mxl111sf_state *state);
|
||||
int mxl111sf_config_mpeg_in(struct mxl111sf_state *state,
|
||||
unsigned int parallel_serial,
|
||||
unsigned int msb_lsb_1st,
|
||||
unsigned int clock_phase,
|
||||
unsigned int mpeg_valid_pol,
|
||||
unsigned int mpeg_sync_pol);
|
||||
int mxl111sf_config_i2s(struct mxl111sf_state *state,
|
||||
u8 msb_start_pos, u8 data_width);
|
||||
int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size);
|
||||
int mxl111sf_disable_i2s_port(struct mxl111sf_state *state);
|
||||
int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff);
|
||||
int mxl111sf_idac_config(struct mxl111sf_state *state,
|
||||
u8 control_mode, u8 current_setting,
|
||||
u8 current_value, u8 hysteresis_value);
|
||||
|
||||
#endif /* _DVB_USB_MXL111SF_PHY_H_ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
179
drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h
Normal file
179
drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* mxl111sf-reg.h - driver for the MaxLinear MXL111SF
|
||||
*
|
||||
* Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* 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 _DVB_USB_MXL111SF_REG_H_
|
||||
#define _DVB_USB_MXL111SF_REG_H_
|
||||
|
||||
#define CHIP_ID_REG 0xFC
|
||||
#define TOP_CHIP_REV_ID_REG 0xFA
|
||||
|
||||
#define V6_SNR_RB_LSB_REG 0x27
|
||||
#define V6_SNR_RB_MSB_REG 0x28
|
||||
|
||||
#define V6_N_ACCUMULATE_REG 0x11
|
||||
#define V6_RS_AVG_ERRORS_LSB_REG 0x2C
|
||||
#define V6_RS_AVG_ERRORS_MSB_REG 0x2D
|
||||
|
||||
#define V6_IRQ_STATUS_REG 0x24
|
||||
#define IRQ_MASK_FEC_LOCK 0x10
|
||||
|
||||
#define V6_SYNC_LOCK_REG 0x28
|
||||
#define SYNC_LOCK_MASK 0x10
|
||||
|
||||
#define V6_RS_LOCK_DET_REG 0x28
|
||||
#define RS_LOCK_DET_MASK 0x08
|
||||
|
||||
#define V6_INITACQ_NODETECT_REG 0x20
|
||||
#define V6_FORCE_NFFT_CPSIZE_REG 0x20
|
||||
|
||||
#define V6_CODE_RATE_TPS_REG 0x29
|
||||
#define V6_CODE_RATE_TPS_MASK 0x07
|
||||
|
||||
|
||||
#define V6_CP_LOCK_DET_REG 0x28
|
||||
#define V6_CP_LOCK_DET_MASK 0x04
|
||||
|
||||
#define V6_TPS_HIERACHY_REG 0x29
|
||||
#define V6_TPS_HIERARCHY_INFO_MASK 0x40
|
||||
|
||||
#define V6_MODORDER_TPS_REG 0x2A
|
||||
#define V6_PARAM_CONSTELLATION_MASK 0x30
|
||||
|
||||
#define V6_MODE_TPS_REG 0x2A
|
||||
#define V6_PARAM_FFT_MODE_MASK 0x0C
|
||||
|
||||
|
||||
#define V6_CP_TPS_REG 0x29
|
||||
#define V6_PARAM_GI_MASK 0x30
|
||||
|
||||
#define V6_TPS_LOCK_REG 0x2A
|
||||
#define V6_PARAM_TPS_LOCK_MASK 0x40
|
||||
|
||||
#define V6_FEC_PER_COUNT_REG 0x2E
|
||||
#define V6_FEC_PER_SCALE_REG 0x2B
|
||||
#define V6_FEC_PER_SCALE_MASK 0x03
|
||||
#define V6_FEC_PER_CLR_REG 0x20
|
||||
#define V6_FEC_PER_CLR_MASK 0x01
|
||||
|
||||
#define V6_PIN_MUX_MODE_REG 0x1B
|
||||
#define V6_ENABLE_PIN_MUX 0x1E
|
||||
|
||||
#define V6_I2S_NUM_SAMPLES_REG 0x16
|
||||
|
||||
#define V6_MPEG_IN_CLK_INV_REG 0x17
|
||||
#define V6_MPEG_IN_CTRL_REG 0x18
|
||||
|
||||
#define V6_INVERTED_CLK_PHASE 0x20
|
||||
#define V6_MPEG_IN_DATA_PARALLEL 0x01
|
||||
#define V6_MPEG_IN_DATA_SERIAL 0x02
|
||||
|
||||
#define V6_INVERTED_MPEG_SYNC 0x04
|
||||
#define V6_INVERTED_MPEG_VALID 0x08
|
||||
|
||||
#define TSIF_INPUT_PARALLEL 0
|
||||
#define TSIF_INPUT_SERIAL 1
|
||||
#define TSIF_NORMAL 0
|
||||
|
||||
#define V6_MPEG_INOUT_BIT_ORDER_CTRL_REG 0x19
|
||||
#define V6_MPEG_SER_MSB_FIRST 0x80
|
||||
#define MPEG_SER_MSB_FIRST_ENABLED 0x01
|
||||
|
||||
#define V6_656_I2S_BUFF_STATUS_REG 0x2F
|
||||
#define V6_656_OVERFLOW_MASK_BIT 0x08
|
||||
#define V6_I2S_OVERFLOW_MASK_BIT 0x01
|
||||
|
||||
#define V6_I2S_STREAM_START_BIT_REG 0x14
|
||||
#define V6_I2S_STREAM_END_BIT_REG 0x15
|
||||
#define I2S_RIGHT_JUSTIFIED 0
|
||||
#define I2S_LEFT_JUSTIFIED 1
|
||||
#define I2S_DATA_FORMAT 2
|
||||
|
||||
#define V6_TUNER_LOOP_THRU_CONTROL_REG 0x09
|
||||
#define V6_ENABLE_LOOP_THRU 0x01
|
||||
|
||||
#define TOTAL_NUM_IF_OUTPUT_FREQ 16
|
||||
|
||||
#define TUNER_NORMAL_IF_SPECTRUM 0x0
|
||||
#define TUNER_INVERT_IF_SPECTRUM 0x10
|
||||
|
||||
#define V6_TUNER_IF_SEL_REG 0x06
|
||||
#define V6_TUNER_IF_FCW_REG 0x3C
|
||||
#define V6_TUNER_IF_FCW_BYP_REG 0x3D
|
||||
#define V6_RF_LOCK_STATUS_REG 0x23
|
||||
|
||||
#define NUM_DIG_TV_CHANNEL 1000
|
||||
|
||||
#define V6_DIG_CLK_FREQ_SEL_REG 0x07
|
||||
#define V6_REF_SYNTH_INT_REG 0x5C
|
||||
#define V6_REF_SYNTH_REMAIN_REG 0x58
|
||||
#define V6_DIG_RFREFSELECT_REG 0x32
|
||||
#define V6_XTAL_CLK_OUT_GAIN_REG 0x31
|
||||
#define V6_TUNER_LOOP_THRU_CTRL_REG 0x09
|
||||
#define V6_DIG_XTAL_ENABLE_REG 0x06
|
||||
#define V6_DIG_XTAL_BIAS_REG 0x66
|
||||
#define V6_XTAL_CAP_REG 0x08
|
||||
|
||||
#define V6_GPO_CTRL_REG 0x18
|
||||
#define MXL_GPO_0 0x00
|
||||
#define MXL_GPO_1 0x01
|
||||
#define V6_GPO_0_MASK 0x10
|
||||
#define V6_GPO_1_MASK 0x20
|
||||
|
||||
#define V6_111SF_GPO_CTRL_REG 0x19
|
||||
#define MXL_111SF_GPO_1 0x00
|
||||
#define MXL_111SF_GPO_2 0x01
|
||||
#define MXL_111SF_GPO_3 0x02
|
||||
#define MXL_111SF_GPO_4 0x03
|
||||
#define MXL_111SF_GPO_5 0x04
|
||||
#define MXL_111SF_GPO_6 0x05
|
||||
#define MXL_111SF_GPO_7 0x06
|
||||
|
||||
#define MXL_111SF_GPO_0_MASK 0x01
|
||||
#define MXL_111SF_GPO_1_MASK 0x02
|
||||
#define MXL_111SF_GPO_2_MASK 0x04
|
||||
#define MXL_111SF_GPO_3_MASK 0x08
|
||||
#define MXL_111SF_GPO_4_MASK 0x10
|
||||
#define MXL_111SF_GPO_5_MASK 0x20
|
||||
#define MXL_111SF_GPO_6_MASK 0x40
|
||||
|
||||
#define V6_ATSC_CONFIG_REG 0x0A
|
||||
|
||||
#define MXL_MODE_REG 0x03
|
||||
#define START_TUNE_REG 0x1C
|
||||
|
||||
#define V6_IDAC_HYSTERESIS_REG 0x0B
|
||||
#define V6_IDAC_SETTINGS_REG 0x0C
|
||||
#define IDAC_MANUAL_CONTROL 1
|
||||
#define IDAC_CURRENT_SINKING_ENABLE 1
|
||||
#define IDAC_MANUAL_CONTROL_BIT_MASK 0x80
|
||||
#define IDAC_CURRENT_SINKING_BIT_MASK 0x40
|
||||
|
||||
#define V8_SPI_MODE_REG 0xE9
|
||||
|
||||
#define V6_DIG_RF_PWR_LSB_REG 0x46
|
||||
#define V6_DIG_RF_PWR_MSB_REG 0x47
|
||||
|
||||
#endif /* _DVB_USB_MXL111SF_REG_H_ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
525
drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
Normal file
525
drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
Normal file
|
|
@ -0,0 +1,525 @@
|
|||
/*
|
||||
* mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner
|
||||
*
|
||||
* Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* 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 "mxl111sf-tuner.h"
|
||||
#include "mxl111sf-phy.h"
|
||||
#include "mxl111sf-reg.h"
|
||||
|
||||
/* debug */
|
||||
static int mxl111sf_tuner_debug;
|
||||
module_param_named(debug, mxl111sf_tuner_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
|
||||
|
||||
#define mxl_dbg(fmt, arg...) \
|
||||
if (mxl111sf_tuner_debug) \
|
||||
mxl_printk(KERN_DEBUG, fmt, ##arg)
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
struct mxl111sf_tuner_state {
|
||||
struct mxl111sf_state *mxl_state;
|
||||
|
||||
struct mxl111sf_tuner_config *cfg;
|
||||
|
||||
enum mxl_if_freq if_freq;
|
||||
|
||||
u32 frequency;
|
||||
u32 bandwidth;
|
||||
};
|
||||
|
||||
static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state,
|
||||
u8 addr, u8 *data)
|
||||
{
|
||||
return (state->cfg->read_reg) ?
|
||||
state->cfg->read_reg(state->mxl_state, addr, data) :
|
||||
-EINVAL;
|
||||
}
|
||||
|
||||
static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state,
|
||||
u8 addr, u8 data)
|
||||
{
|
||||
return (state->cfg->write_reg) ?
|
||||
state->cfg->write_reg(state->mxl_state, addr, data) :
|
||||
-EINVAL;
|
||||
}
|
||||
|
||||
static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state,
|
||||
struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
|
||||
{
|
||||
return (state->cfg->program_regs) ?
|
||||
state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
|
||||
-EINVAL;
|
||||
}
|
||||
|
||||
static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state,
|
||||
int onoff)
|
||||
{
|
||||
return (state->cfg->top_master_ctrl) ?
|
||||
state->cfg->top_master_ctrl(state->mxl_state, onoff) :
|
||||
-EINVAL;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = {
|
||||
{0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3,
|
||||
DIG_MODEINDEX, _A, _CSF, */
|
||||
{0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */
|
||||
{0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq,
|
||||
u8 bw)
|
||||
{
|
||||
u8 filt_bw;
|
||||
|
||||
/* set channel bandwidth */
|
||||
switch (bw) {
|
||||
case 0: /* ATSC */
|
||||
filt_bw = 25;
|
||||
break;
|
||||
case 1: /* QAM */
|
||||
filt_bw = 69;
|
||||
break;
|
||||
case 6:
|
||||
filt_bw = 21;
|
||||
break;
|
||||
case 7:
|
||||
filt_bw = 42;
|
||||
break;
|
||||
case 8:
|
||||
filt_bw = 63;
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: invalid bandwidth setting!", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* calculate RF channel */
|
||||
freq /= 1000000;
|
||||
|
||||
freq *= 64;
|
||||
#if 0
|
||||
/* do round */
|
||||
freq += 0.5;
|
||||
#endif
|
||||
/* set bandwidth */
|
||||
mxl_phy_tune_rf[0].data = filt_bw;
|
||||
|
||||
/* set RF */
|
||||
mxl_phy_tune_rf[1].data = (freq & 0xff);
|
||||
mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff;
|
||||
|
||||
/* start tune */
|
||||
return mxl_phy_tune_rf;
|
||||
}
|
||||
|
||||
static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state)
|
||||
{
|
||||
int ret;
|
||||
u8 ctrl;
|
||||
#if 0
|
||||
u16 iffcw;
|
||||
u32 if_freq;
|
||||
#endif
|
||||
mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)",
|
||||
state->cfg->invert_spectrum, state->cfg->if_freq);
|
||||
|
||||
/* set IF polarity */
|
||||
ctrl = state->cfg->invert_spectrum;
|
||||
|
||||
ctrl |= state->cfg->if_freq;
|
||||
|
||||
ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
#if 0
|
||||
if_freq /= 1000000;
|
||||
|
||||
/* do round */
|
||||
if_freq += 0.5;
|
||||
|
||||
if (MXL_IF_LO == state->cfg->if_freq) {
|
||||
ctrl = 0x08;
|
||||
iffcw = (u16)(if_freq / (108 * 4096));
|
||||
} else if (MXL_IF_HI == state->cfg->if_freq) {
|
||||
ctrl = 0x08;
|
||||
iffcw = (u16)(if_freq / (216 * 4096));
|
||||
} else {
|
||||
ctrl = 0;
|
||||
iffcw = 0;
|
||||
}
|
||||
|
||||
ctrl |= (iffcw >> 8);
|
||||
#endif
|
||||
ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
ctrl &= 0xf0;
|
||||
ctrl |= 0x90;
|
||||
|
||||
ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
#if 0
|
||||
ctrl = iffcw & 0x00ff;
|
||||
#endif
|
||||
ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
state->if_freq = state->cfg->if_freq;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw)
|
||||
{
|
||||
struct mxl111sf_tuner_state *state = fe->tuner_priv;
|
||||
static struct mxl111sf_reg_ctrl_info *reg_ctrl_array;
|
||||
int ret;
|
||||
u8 mxl_mode;
|
||||
|
||||
mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw);
|
||||
|
||||
/* stop tune */
|
||||
ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
/* check device mode */
|
||||
ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
/* Fill out registers for channel tune */
|
||||
reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw);
|
||||
if (!reg_ctrl_array)
|
||||
return -EINVAL;
|
||||
|
||||
ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) {
|
||||
/* IF tuner mode only */
|
||||
mxl1x1sf_tuner_top_master_ctrl(state, 0);
|
||||
mxl1x1sf_tuner_top_master_ctrl(state, 1);
|
||||
mxl1x1sf_tuner_set_if_output_freq(state);
|
||||
}
|
||||
|
||||
ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
if (state->cfg->ant_hunt)
|
||||
state->cfg->ant_hunt(fe);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state,
|
||||
int *rf_synth_lock,
|
||||
int *ref_synth_lock)
|
||||
{
|
||||
int ret;
|
||||
u8 data;
|
||||
|
||||
*rf_synth_lock = 0;
|
||||
*ref_synth_lock = 0;
|
||||
|
||||
ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
*ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0;
|
||||
*rf_synth_lock = ((data & 0x0c) == 0x0c) ? 1 : 0;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state,
|
||||
int onoff)
|
||||
{
|
||||
return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG,
|
||||
onoff ? 1 : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static int mxl111sf_tuner_set_params(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
u32 delsys = c->delivery_system;
|
||||
struct mxl111sf_tuner_state *state = fe->tuner_priv;
|
||||
int ret;
|
||||
u8 bw;
|
||||
|
||||
mxl_dbg("()");
|
||||
|
||||
switch (delsys) {
|
||||
case SYS_ATSC:
|
||||
case SYS_ATSCMH:
|
||||
bw = 0; /* ATSC */
|
||||
break;
|
||||
case SYS_DVBC_ANNEX_B:
|
||||
bw = 1; /* US CABLE */
|
||||
break;
|
||||
case SYS_DVBT:
|
||||
switch (c->bandwidth_hz) {
|
||||
case 6000000:
|
||||
bw = 6;
|
||||
break;
|
||||
case 7000000:
|
||||
bw = 7;
|
||||
break;
|
||||
case 8000000:
|
||||
bw = 8;
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: bandwidth not set!", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: modulation type not supported!", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = mxl1x1sf_tune_rf(fe, c->frequency, bw);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
state->frequency = c->frequency;
|
||||
state->bandwidth = c->bandwidth_hz;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#if 0
|
||||
static int mxl111sf_tuner_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct mxl111sf_tuner_state *state = fe->tuner_priv;
|
||||
int ret;
|
||||
|
||||
/* wake from standby handled by usb driver */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_tuner_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct mxl111sf_tuner_state *state = fe->tuner_priv;
|
||||
int ret;
|
||||
|
||||
/* enter standby mode handled by usb driver */
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status)
|
||||
{
|
||||
struct mxl111sf_tuner_state *state = fe->tuner_priv;
|
||||
int rf_locked, ref_locked, ret;
|
||||
|
||||
*status = 0;
|
||||
|
||||
ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
mxl_info("%s%s", rf_locked ? "rf locked " : "",
|
||||
ref_locked ? "ref locked" : "");
|
||||
|
||||
if ((rf_locked) || (ref_locked))
|
||||
*status |= TUNER_STATUS_LOCKED;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
|
||||
{
|
||||
struct mxl111sf_tuner_state *state = fe->tuner_priv;
|
||||
u8 val1, val2;
|
||||
int ret;
|
||||
|
||||
*strength = 0;
|
||||
|
||||
ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2);
|
||||
if (mxl_fail(ret))
|
||||
goto fail;
|
||||
|
||||
*strength = val1 | ((val2 & 0x07) << 8);
|
||||
fail:
|
||||
ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00);
|
||||
mxl_fail(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency)
|
||||
{
|
||||
struct mxl111sf_tuner_state *state = fe->tuner_priv;
|
||||
*frequency = state->frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
|
||||
{
|
||||
struct mxl111sf_tuner_state *state = fe->tuner_priv;
|
||||
*bandwidth = state->bandwidth;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe,
|
||||
u32 *frequency)
|
||||
{
|
||||
struct mxl111sf_tuner_state *state = fe->tuner_priv;
|
||||
|
||||
*frequency = 0;
|
||||
|
||||
switch (state->if_freq) {
|
||||
case MXL_IF_4_0: /* 4.0 MHz */
|
||||
*frequency = 4000000;
|
||||
break;
|
||||
case MXL_IF_4_5: /* 4.5 MHz */
|
||||
*frequency = 4500000;
|
||||
break;
|
||||
case MXL_IF_4_57: /* 4.57 MHz */
|
||||
*frequency = 4570000;
|
||||
break;
|
||||
case MXL_IF_5_0: /* 5.0 MHz */
|
||||
*frequency = 5000000;
|
||||
break;
|
||||
case MXL_IF_5_38: /* 5.38 MHz */
|
||||
*frequency = 5380000;
|
||||
break;
|
||||
case MXL_IF_6_0: /* 6.0 MHz */
|
||||
*frequency = 6000000;
|
||||
break;
|
||||
case MXL_IF_6_28: /* 6.28 MHz */
|
||||
*frequency = 6280000;
|
||||
break;
|
||||
case MXL_IF_7_2: /* 7.2 MHz */
|
||||
*frequency = 7200000;
|
||||
break;
|
||||
case MXL_IF_35_25: /* 35.25 MHz */
|
||||
*frequency = 35250000;
|
||||
break;
|
||||
case MXL_IF_36: /* 36 MHz */
|
||||
*frequency = 36000000;
|
||||
break;
|
||||
case MXL_IF_36_15: /* 36.15 MHz */
|
||||
*frequency = 36150000;
|
||||
break;
|
||||
case MXL_IF_44: /* 44 MHz */
|
||||
*frequency = 44000000;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxl111sf_tuner_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct mxl111sf_tuner_state *state = fe->tuner_priv;
|
||||
mxl_dbg("()");
|
||||
kfree(state);
|
||||
fe->tuner_priv = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = {
|
||||
.info = {
|
||||
.name = "MaxLinear MxL111SF",
|
||||
#if 0
|
||||
.frequency_min = ,
|
||||
.frequency_max = ,
|
||||
.frequency_step = ,
|
||||
#endif
|
||||
},
|
||||
#if 0
|
||||
.init = mxl111sf_tuner_init,
|
||||
.sleep = mxl111sf_tuner_sleep,
|
||||
#endif
|
||||
.set_params = mxl111sf_tuner_set_params,
|
||||
.get_status = mxl111sf_tuner_get_status,
|
||||
.get_rf_strength = mxl111sf_get_rf_strength,
|
||||
.get_frequency = mxl111sf_tuner_get_frequency,
|
||||
.get_bandwidth = mxl111sf_tuner_get_bandwidth,
|
||||
.get_if_frequency = mxl111sf_tuner_get_if_frequency,
|
||||
.release = mxl111sf_tuner_release,
|
||||
};
|
||||
|
||||
struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
|
||||
struct mxl111sf_state *mxl_state,
|
||||
struct mxl111sf_tuner_config *cfg)
|
||||
{
|
||||
struct mxl111sf_tuner_state *state = NULL;
|
||||
|
||||
mxl_dbg("()");
|
||||
|
||||
state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
return NULL;
|
||||
|
||||
state->mxl_state = mxl_state;
|
||||
state->cfg = cfg;
|
||||
|
||||
memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops,
|
||||
sizeof(struct dvb_tuner_ops));
|
||||
|
||||
fe->tuner_priv = state;
|
||||
return fe;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach);
|
||||
|
||||
MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver");
|
||||
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("0.1");
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
88
drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
Normal file
88
drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* mxl111sf-tuner.h - driver for the MaxLinear MXL111SF CMOS tuner
|
||||
*
|
||||
* Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* 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 __MXL111SF_TUNER_H__
|
||||
#define __MXL111SF_TUNER_H__
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "mxl111sf.h"
|
||||
|
||||
enum mxl_if_freq {
|
||||
#if 0
|
||||
MXL_IF_LO = 0x00, /* other IF < 9MHz */
|
||||
#endif
|
||||
MXL_IF_4_0 = 0x01, /* 4.0 MHz */
|
||||
MXL_IF_4_5 = 0x02, /* 4.5 MHz */
|
||||
MXL_IF_4_57 = 0x03, /* 4.57 MHz */
|
||||
MXL_IF_5_0 = 0x04, /* 5.0 MHz */
|
||||
MXL_IF_5_38 = 0x05, /* 5.38 MHz */
|
||||
MXL_IF_6_0 = 0x06, /* 6.0 MHz */
|
||||
MXL_IF_6_28 = 0x07, /* 6.28 MHz */
|
||||
MXL_IF_7_2 = 0x08, /* 7.2 MHz */
|
||||
MXL_IF_35_25 = 0x09, /* 35.25 MHz */
|
||||
MXL_IF_36 = 0x0a, /* 36 MHz */
|
||||
MXL_IF_36_15 = 0x0b, /* 36.15 MHz */
|
||||
MXL_IF_44 = 0x0c, /* 44 MHz */
|
||||
#if 0
|
||||
MXL_IF_HI = 0x0f, /* other IF > 35 MHz and < 45 MHz */
|
||||
#endif
|
||||
};
|
||||
|
||||
struct mxl111sf_tuner_config {
|
||||
enum mxl_if_freq if_freq;
|
||||
unsigned int invert_spectrum:1;
|
||||
|
||||
int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data);
|
||||
int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data);
|
||||
int (*program_regs)(struct mxl111sf_state *state,
|
||||
struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
|
||||
int (*top_master_ctrl)(struct mxl111sf_state *state, int onoff);
|
||||
int (*ant_hunt)(struct dvb_frontend *fe);
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#if IS_ENABLED(CONFIG_DVB_USB_MXL111SF)
|
||||
extern
|
||||
struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
|
||||
struct mxl111sf_state *mxl_state,
|
||||
struct mxl111sf_tuner_config *cfg);
|
||||
#else
|
||||
static inline
|
||||
struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
|
||||
struct mxl111sf_state *mxl_state,
|
||||
struct mxl111sf_tuner_config *cfg)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MXL111SF_TUNER_H__ */
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
|
||||
1433
drivers/media/usb/dvb-usb-v2/mxl111sf.c
Normal file
1433
drivers/media/usb/dvb-usb-v2/mxl111sf.c
Normal file
File diff suppressed because it is too large
Load diff
160
drivers/media/usb/dvb-usb-v2/mxl111sf.h
Normal file
160
drivers/media/usb/dvb-usb-v2/mxl111sf.h
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Copyright (C) 2010-2014 Michael Krufky (mkrufky@linuxtv.org)
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
|
||||
#ifndef _DVB_USB_MXL111SF_H_
|
||||
#define _DVB_USB_MXL111SF_H_
|
||||
|
||||
#ifdef DVB_USB_LOG_PREFIX
|
||||
#undef DVB_USB_LOG_PREFIX
|
||||
#endif
|
||||
#define DVB_USB_LOG_PREFIX "mxl111sf"
|
||||
#include "dvb_usb.h"
|
||||
#include <media/tveeprom.h>
|
||||
|
||||
#define MXL_EP1_REG_READ 1
|
||||
#define MXL_EP2_REG_WRITE 2
|
||||
#define MXL_EP3_INTERRUPT 3
|
||||
#define MXL_EP4_MPEG2 4
|
||||
#define MXL_EP5_I2S 5
|
||||
#define MXL_EP6_656 6
|
||||
#define MXL_EP6_MPEG2 6
|
||||
|
||||
#ifdef USING_ENUM_mxl111sf_current_mode
|
||||
enum mxl111sf_current_mode {
|
||||
mxl_mode_dvbt = MXL_EP4_MPEG2,
|
||||
mxl_mode_mh = MXL_EP5_I2S,
|
||||
mxl_mode_atsc = MXL_EP6_MPEG2,
|
||||
};
|
||||
#endif
|
||||
|
||||
enum mxl111sf_gpio_port_expander {
|
||||
mxl111sf_gpio_hw,
|
||||
mxl111sf_PCA9534,
|
||||
};
|
||||
|
||||
struct mxl111sf_adap_state {
|
||||
int alt_mode;
|
||||
int gpio_mode;
|
||||
int device_mode;
|
||||
int ep6_clockphase;
|
||||
int (*fe_init)(struct dvb_frontend *);
|
||||
int (*fe_sleep)(struct dvb_frontend *);
|
||||
};
|
||||
|
||||
struct mxl111sf_state {
|
||||
struct dvb_usb_device *d;
|
||||
|
||||
enum mxl111sf_gpio_port_expander gpio_port_expander;
|
||||
u8 port_expander_addr;
|
||||
|
||||
u8 chip_id;
|
||||
u8 chip_ver;
|
||||
#define MXL111SF_V6 1
|
||||
#define MXL111SF_V8_100 2
|
||||
#define MXL111SF_V8_200 3
|
||||
u8 chip_rev;
|
||||
|
||||
#ifdef USING_ENUM_mxl111sf_current_mode
|
||||
enum mxl111sf_current_mode current_mode;
|
||||
#endif
|
||||
|
||||
#define MXL_TUNER_MODE 0
|
||||
#define MXL_SOC_MODE 1
|
||||
#define MXL_DEV_MODE_MASK 0x01
|
||||
#if 1
|
||||
int device_mode;
|
||||
#endif
|
||||
/* use usb alt setting 1 for EP4 ISOC transfer (dvb-t),
|
||||
EP5 BULK transfer (atsc-mh),
|
||||
EP6 BULK transfer (atsc/qam),
|
||||
use usb alt setting 2 for EP4 BULK transfer (dvb-t),
|
||||
EP5 ISOC transfer (atsc-mh),
|
||||
EP6 ISOC transfer (atsc/qam),
|
||||
*/
|
||||
int alt_mode;
|
||||
int gpio_mode;
|
||||
struct tveeprom tv;
|
||||
|
||||
struct mutex fe_lock;
|
||||
u8 num_frontends;
|
||||
struct mxl111sf_adap_state adap_state[3];
|
||||
};
|
||||
|
||||
int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data);
|
||||
int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data);
|
||||
|
||||
struct mxl111sf_reg_ctrl_info {
|
||||
u8 addr;
|
||||
u8 mask;
|
||||
u8 data;
|
||||
};
|
||||
|
||||
int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
|
||||
u8 addr, u8 mask, u8 data);
|
||||
int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
|
||||
struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
|
||||
|
||||
/* needed for hardware i2c functions in mxl111sf-i2c.c:
|
||||
* mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */
|
||||
int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
|
||||
u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen);
|
||||
|
||||
#define mxl_printk(kern, fmt, arg...) \
|
||||
printk(kern "%s: " fmt "\n", __func__, ##arg)
|
||||
|
||||
#define mxl_info(fmt, arg...) \
|
||||
mxl_printk(KERN_INFO, fmt, ##arg)
|
||||
|
||||
extern int dvb_usb_mxl111sf_debug;
|
||||
#define mxl_debug(fmt, arg...) \
|
||||
if (dvb_usb_mxl111sf_debug) \
|
||||
mxl_printk(KERN_DEBUG, fmt, ##arg)
|
||||
|
||||
#define MXL_I2C_DBG 0x04
|
||||
#define MXL_ADV_DBG 0x10
|
||||
#define mxl_debug_adv(fmt, arg...) \
|
||||
if (dvb_usb_mxl111sf_debug & MXL_ADV_DBG) \
|
||||
mxl_printk(KERN_DEBUG, fmt, ##arg)
|
||||
|
||||
#define mxl_i2c(fmt, arg...) \
|
||||
if (dvb_usb_mxl111sf_debug & MXL_I2C_DBG) \
|
||||
mxl_printk(KERN_DEBUG, fmt, ##arg)
|
||||
|
||||
#define mxl_i2c_adv(fmt, arg...) \
|
||||
if ((dvb_usb_mxl111sf_debug & (MXL_I2C_DBG | MXL_ADV_DBG)) == \
|
||||
(MXL_I2C_DBG | MXL_ADV_DBG)) \
|
||||
mxl_printk(KERN_DEBUG, fmt, ##arg)
|
||||
|
||||
/* The following allows the mxl_fail() macro defined below to work
|
||||
* in externel modules, such as mxl111sf-tuner.ko, even though
|
||||
* dvb_usb_mxl111sf_debug is not defined within those modules */
|
||||
#if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__))
|
||||
#define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG
|
||||
#else
|
||||
#define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug
|
||||
#endif
|
||||
|
||||
#define mxl_fail(ret) \
|
||||
({ \
|
||||
int __ret; \
|
||||
__ret = (ret < 0); \
|
||||
if ((__ret) && (MXL_ADV_DEBUG_ENABLED & MXL_ADV_DBG)) \
|
||||
mxl_printk(KERN_ERR, "error %d on line %d", \
|
||||
ret, __LINE__); \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#endif /* _DVB_USB_MXL111SF_H_ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
1573
drivers/media/usb/dvb-usb-v2/rtl28xxu.c
Normal file
1573
drivers/media/usb/dvb-usb-v2/rtl28xxu.c
Normal file
File diff suppressed because it is too large
Load diff
255
drivers/media/usb/dvb-usb-v2/rtl28xxu.h
Normal file
255
drivers/media/usb/dvb-usb-v2/rtl28xxu.h
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Realtek RTL28xxU DVB USB driver
|
||||
*
|
||||
* Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
|
||||
* Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef RTL28XXU_H
|
||||
#define RTL28XXU_H
|
||||
|
||||
#include "dvb_usb.h"
|
||||
|
||||
/*
|
||||
* USB commands
|
||||
* (usb_control_msg() index parameter)
|
||||
*/
|
||||
|
||||
#define DEMOD 0x0000
|
||||
#define USB 0x0100
|
||||
#define SYS 0x0200
|
||||
#define I2C 0x0300
|
||||
#define I2C_DA 0x0600
|
||||
|
||||
#define CMD_WR_FLAG 0x0010
|
||||
#define CMD_DEMOD_RD 0x0000
|
||||
#define CMD_DEMOD_WR 0x0010
|
||||
#define CMD_USB_RD 0x0100
|
||||
#define CMD_USB_WR 0x0110
|
||||
#define CMD_SYS_RD 0x0200
|
||||
#define CMD_IR_RD 0x0201
|
||||
#define CMD_IR_WR 0x0211
|
||||
#define CMD_SYS_WR 0x0210
|
||||
#define CMD_I2C_RD 0x0300
|
||||
#define CMD_I2C_WR 0x0310
|
||||
#define CMD_I2C_DA_RD 0x0600
|
||||
#define CMD_I2C_DA_WR 0x0610
|
||||
|
||||
|
||||
struct rtl28xxu_priv {
|
||||
u8 chip_id;
|
||||
u8 tuner;
|
||||
char *tuner_name;
|
||||
u8 page; /* integrated demod active register page */
|
||||
struct i2c_adapter *demod_i2c_adapter;
|
||||
bool rc_active;
|
||||
struct i2c_client *client;
|
||||
};
|
||||
|
||||
enum rtl28xxu_chip_id {
|
||||
CHIP_ID_NONE,
|
||||
CHIP_ID_RTL2831U,
|
||||
CHIP_ID_RTL2832U,
|
||||
};
|
||||
|
||||
/* XXX: Hack. This must be keep sync with rtl2832 demod driver. */
|
||||
enum rtl28xxu_tuner {
|
||||
TUNER_NONE,
|
||||
|
||||
TUNER_RTL2830_QT1010 = 0x10,
|
||||
TUNER_RTL2830_MT2060,
|
||||
TUNER_RTL2830_MXL5005S,
|
||||
|
||||
TUNER_RTL2832_MT2266 = 0x20,
|
||||
TUNER_RTL2832_FC2580,
|
||||
TUNER_RTL2832_MT2063,
|
||||
TUNER_RTL2832_MAX3543,
|
||||
TUNER_RTL2832_TUA9001,
|
||||
TUNER_RTL2832_MXL5007T,
|
||||
TUNER_RTL2832_FC0012,
|
||||
TUNER_RTL2832_E4000,
|
||||
TUNER_RTL2832_TDA18272,
|
||||
TUNER_RTL2832_FC0013,
|
||||
TUNER_RTL2832_R820T,
|
||||
TUNER_RTL2832_R828D,
|
||||
};
|
||||
|
||||
struct rtl28xxu_req {
|
||||
u16 value;
|
||||
u16 index;
|
||||
u16 size;
|
||||
u8 *data;
|
||||
};
|
||||
|
||||
struct rtl28xxu_reg_val {
|
||||
u16 reg;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
struct rtl28xxu_reg_val_mask {
|
||||
u16 reg;
|
||||
u8 val;
|
||||
u8 mask;
|
||||
};
|
||||
|
||||
/*
|
||||
* memory map
|
||||
*
|
||||
* 0x0000 DEMOD : demodulator
|
||||
* 0x2000 USB : SIE, USB endpoint, debug, DMA
|
||||
* 0x3000 SYS : system
|
||||
* 0xfc00 RC : remote controller (not RTL2831U)
|
||||
*/
|
||||
|
||||
/*
|
||||
* USB registers
|
||||
*/
|
||||
/* SIE Control Registers */
|
||||
#define USB_SYSCTL 0x2000 /* USB system control */
|
||||
#define USB_SYSCTL_0 0x2000 /* USB system control */
|
||||
#define USB_SYSCTL_1 0x2001 /* USB system control */
|
||||
#define USB_SYSCTL_2 0x2002 /* USB system control */
|
||||
#define USB_SYSCTL_3 0x2003 /* USB system control */
|
||||
#define USB_IRQSTAT 0x2008 /* SIE interrupt status */
|
||||
#define USB_IRQEN 0x200C /* SIE interrupt enable */
|
||||
#define USB_CTRL 0x2010 /* USB control */
|
||||
#define USB_STAT 0x2014 /* USB status */
|
||||
#define USB_DEVADDR 0x2018 /* USB device address */
|
||||
#define USB_TEST 0x201C /* USB test mode */
|
||||
#define USB_FRAME_NUMBER 0x2020 /* frame number */
|
||||
#define USB_FIFO_ADDR 0x2028 /* address of SIE FIFO RAM */
|
||||
#define USB_FIFO_CMD 0x202A /* SIE FIFO RAM access command */
|
||||
#define USB_FIFO_DATA 0x2030 /* SIE FIFO RAM data */
|
||||
/* Endpoint Registers */
|
||||
#define EP0_SETUPA 0x20F8 /* EP 0 setup packet lower byte */
|
||||
#define EP0_SETUPB 0x20FC /* EP 0 setup packet higher byte */
|
||||
#define USB_EP0_CFG 0x2104 /* EP 0 configure */
|
||||
#define USB_EP0_CTL 0x2108 /* EP 0 control */
|
||||
#define USB_EP0_STAT 0x210C /* EP 0 status */
|
||||
#define USB_EP0_IRQSTAT 0x2110 /* EP 0 interrupt status */
|
||||
#define USB_EP0_IRQEN 0x2114 /* EP 0 interrupt enable */
|
||||
#define USB_EP0_MAXPKT 0x2118 /* EP 0 max packet size */
|
||||
#define USB_EP0_BC 0x2120 /* EP 0 FIFO byte counter */
|
||||
#define USB_EPA_CFG 0x2144 /* EP A configure */
|
||||
#define USB_EPA_CFG_0 0x2144 /* EP A configure */
|
||||
#define USB_EPA_CFG_1 0x2145 /* EP A configure */
|
||||
#define USB_EPA_CFG_2 0x2146 /* EP A configure */
|
||||
#define USB_EPA_CFG_3 0x2147 /* EP A configure */
|
||||
#define USB_EPA_CTL 0x2148 /* EP A control */
|
||||
#define USB_EPA_CTL_0 0x2148 /* EP A control */
|
||||
#define USB_EPA_CTL_1 0x2149 /* EP A control */
|
||||
#define USB_EPA_CTL_2 0x214A /* EP A control */
|
||||
#define USB_EPA_CTL_3 0x214B /* EP A control */
|
||||
#define USB_EPA_STAT 0x214C /* EP A status */
|
||||
#define USB_EPA_IRQSTAT 0x2150 /* EP A interrupt status */
|
||||
#define USB_EPA_IRQEN 0x2154 /* EP A interrupt enable */
|
||||
#define USB_EPA_MAXPKT 0x2158 /* EP A max packet size */
|
||||
#define USB_EPA_MAXPKT_0 0x2158 /* EP A max packet size */
|
||||
#define USB_EPA_MAXPKT_1 0x2159 /* EP A max packet size */
|
||||
#define USB_EPA_MAXPKT_2 0x215A /* EP A max packet size */
|
||||
#define USB_EPA_MAXPKT_3 0x215B /* EP A max packet size */
|
||||
#define USB_EPA_FIFO_CFG 0x2160 /* EP A FIFO configure */
|
||||
#define USB_EPA_FIFO_CFG_0 0x2160 /* EP A FIFO configure */
|
||||
#define USB_EPA_FIFO_CFG_1 0x2161 /* EP A FIFO configure */
|
||||
#define USB_EPA_FIFO_CFG_2 0x2162 /* EP A FIFO configure */
|
||||
#define USB_EPA_FIFO_CFG_3 0x2163 /* EP A FIFO configure */
|
||||
/* Debug Registers */
|
||||
#define USB_PHYTSTDIS 0x2F04 /* PHY test disable */
|
||||
#define USB_TOUT_VAL 0x2F08 /* USB time-out time */
|
||||
#define USB_VDRCTRL 0x2F10 /* UTMI vendor signal control */
|
||||
#define USB_VSTAIN 0x2F14 /* UTMI vendor signal status in */
|
||||
#define USB_VLOADM 0x2F18 /* UTMI load vendor signal status in */
|
||||
#define USB_VSTAOUT 0x2F1C /* UTMI vendor signal status out */
|
||||
#define USB_UTMI_TST 0x2F80 /* UTMI test */
|
||||
#define USB_UTMI_STATUS 0x2F84 /* UTMI status */
|
||||
#define USB_TSTCTL 0x2F88 /* test control */
|
||||
#define USB_TSTCTL2 0x2F8C /* test control 2 */
|
||||
#define USB_PID_FORCE 0x2F90 /* force PID */
|
||||
#define USB_PKTERR_CNT 0x2F94 /* packet error counter */
|
||||
#define USB_RXERR_CNT 0x2F98 /* RX error counter */
|
||||
#define USB_MEM_BIST 0x2F9C /* MEM BIST test */
|
||||
#define USB_SLBBIST 0x2FA0 /* self-loop-back BIST */
|
||||
#define USB_CNTTEST 0x2FA4 /* counter test */
|
||||
#define USB_PHYTST 0x2FC0 /* USB PHY test */
|
||||
#define USB_DBGIDX 0x2FF0 /* select individual block debug signal */
|
||||
#define USB_DBGMUX 0x2FF4 /* debug signal module mux */
|
||||
|
||||
/*
|
||||
* SYS registers
|
||||
*/
|
||||
/* demod control registers */
|
||||
#define SYS_SYS0 0x3000 /* include DEMOD_CTL, GPO, GPI, GPOE */
|
||||
#define SYS_DEMOD_CTL 0x3000 /* control register for DVB-T demodulator */
|
||||
/* GPIO registers */
|
||||
#define SYS_GPIO_OUT_VAL 0x3001 /* output value of GPIO */
|
||||
#define SYS_GPIO_IN_VAL 0x3002 /* input value of GPIO */
|
||||
#define SYS_GPIO_OUT_EN 0x3003 /* output enable of GPIO */
|
||||
#define SYS_SYS1 0x3004 /* include GPD, SYSINTE, SYSINTS, GP_CFG0 */
|
||||
#define SYS_GPIO_DIR 0x3004 /* direction control for GPIO */
|
||||
#define SYS_SYSINTE 0x3005 /* system interrupt enable */
|
||||
#define SYS_SYSINTS 0x3006 /* system interrupt status */
|
||||
#define SYS_GPIO_CFG0 0x3007 /* PAD configuration for GPIO0-GPIO3 */
|
||||
#define SYS_SYS2 0x3008 /* include GP_CFG1 and 3 reserved bytes */
|
||||
#define SYS_GPIO_CFG1 0x3008 /* PAD configuration for GPIO4 */
|
||||
#define SYS_DEMOD_CTL1 0x300B
|
||||
|
||||
/* IrDA registers */
|
||||
#define SYS_IRRC_PSR 0x3020 /* IR protocol selection */
|
||||
#define SYS_IRRC_PER 0x3024 /* IR protocol extension */
|
||||
#define SYS_IRRC_SF 0x3028 /* IR sampling frequency */
|
||||
#define SYS_IRRC_DPIR 0x302C /* IR data package interval */
|
||||
#define SYS_IRRC_CR 0x3030 /* IR control */
|
||||
#define SYS_IRRC_RP 0x3034 /* IR read port */
|
||||
#define SYS_IRRC_SR 0x3038 /* IR status */
|
||||
/* I2C master registers */
|
||||
#define SYS_I2CCR 0x3040 /* I2C clock */
|
||||
#define SYS_I2CMCR 0x3044 /* I2C master control */
|
||||
#define SYS_I2CMSTR 0x3048 /* I2C master SCL timing */
|
||||
#define SYS_I2CMSR 0x304C /* I2C master status */
|
||||
#define SYS_I2CMFR 0x3050 /* I2C master FIFO */
|
||||
|
||||
/*
|
||||
* IR registers
|
||||
*/
|
||||
#define IR_RX_BUF 0xFC00
|
||||
#define IR_RX_IE 0xFD00
|
||||
#define IR_RX_IF 0xFD01
|
||||
#define IR_RX_CTRL 0xFD02
|
||||
#define IR_RX_CFG 0xFD03
|
||||
#define IR_MAX_DURATION0 0xFD04
|
||||
#define IR_MAX_DURATION1 0xFD05
|
||||
#define IR_IDLE_LEN0 0xFD06
|
||||
#define IR_IDLE_LEN1 0xFD07
|
||||
#define IR_GLITCH_LEN 0xFD08
|
||||
#define IR_RX_BUF_CTRL 0xFD09
|
||||
#define IR_RX_BUF_DATA 0xFD0A
|
||||
#define IR_RX_BC 0xFD0B
|
||||
#define IR_RX_CLK 0xFD0C
|
||||
#define IR_RX_C_COUNT_L 0xFD0D
|
||||
#define IR_RX_C_COUNT_H 0xFD0E
|
||||
#define IR_SUSPEND_CTRL 0xFD10
|
||||
#define IR_ERR_TOL_CTRL 0xFD11
|
||||
#define IR_UNIT_LEN 0xFD12
|
||||
#define IR_ERR_TOL_LEN 0xFD13
|
||||
#define IR_MAX_H_TOL_LEN 0xFD14
|
||||
#define IR_MAX_L_TOL_LEN 0xFD15
|
||||
#define IR_MASK_CTRL 0xFD16
|
||||
#define IR_MASK_DATA 0xFD17
|
||||
#define IR_RES_MASK_ADDR 0xFD18
|
||||
#define IR_RES_MASK_T_LEN 0xFD19
|
||||
|
||||
#endif
|
||||
362
drivers/media/usb/dvb-usb-v2/usb_urb.c
Normal file
362
drivers/media/usb/dvb-usb-v2/usb_urb.c
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
/* usb-urb.c is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* This file keeps functions for initializing and handling the
|
||||
* BULK and ISOC USB data transfers in a generic way.
|
||||
* Can be used for DVB-only and also, that's the plan, for
|
||||
* Hybrid USB devices (analog and DVB).
|
||||
*/
|
||||
#include "dvb_usb_common.h"
|
||||
|
||||
/* URB stuff for streaming */
|
||||
|
||||
int usb_urb_reconfig(struct usb_data_stream *stream,
|
||||
struct usb_data_stream_properties *props);
|
||||
|
||||
static void usb_urb_complete(struct urb *urb)
|
||||
{
|
||||
struct usb_data_stream *stream = urb->context;
|
||||
int ptype = usb_pipetype(urb->pipe);
|
||||
int i;
|
||||
u8 *b;
|
||||
|
||||
dev_dbg_ratelimited(&stream->udev->dev,
|
||||
"%s: %s urb completed status=%d length=%d/%d pack_num=%d errors=%d\n",
|
||||
__func__, ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
|
||||
urb->status, urb->actual_length,
|
||||
urb->transfer_buffer_length,
|
||||
urb->number_of_packets, urb->error_count);
|
||||
|
||||
switch (urb->status) {
|
||||
case 0: /* success */
|
||||
case -ETIMEDOUT: /* NAK */
|
||||
break;
|
||||
case -ECONNRESET: /* kill */
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
return;
|
||||
default: /* error */
|
||||
dev_dbg_ratelimited(&stream->udev->dev,
|
||||
"%s: urb completition failed=%d\n",
|
||||
__func__, urb->status);
|
||||
break;
|
||||
}
|
||||
|
||||
b = (u8 *) urb->transfer_buffer;
|
||||
switch (ptype) {
|
||||
case PIPE_ISOCHRONOUS:
|
||||
for (i = 0; i < urb->number_of_packets; i++) {
|
||||
if (urb->iso_frame_desc[i].status != 0)
|
||||
dev_dbg(&stream->udev->dev,
|
||||
"%s: iso frame descriptor has an error=%d\n",
|
||||
__func__,
|
||||
urb->iso_frame_desc[i].status);
|
||||
else if (urb->iso_frame_desc[i].actual_length > 0)
|
||||
stream->complete(stream,
|
||||
b + urb->iso_frame_desc[i].offset,
|
||||
urb->iso_frame_desc[i].actual_length);
|
||||
|
||||
urb->iso_frame_desc[i].status = 0;
|
||||
urb->iso_frame_desc[i].actual_length = 0;
|
||||
}
|
||||
break;
|
||||
case PIPE_BULK:
|
||||
if (urb->actual_length > 0)
|
||||
stream->complete(stream, b, urb->actual_length);
|
||||
break;
|
||||
default:
|
||||
dev_err(&stream->udev->dev,
|
||||
"%s: unknown endpoint type in completition handler\n",
|
||||
KBUILD_MODNAME);
|
||||
return;
|
||||
}
|
||||
usb_submit_urb(urb, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
int usb_urb_killv2(struct usb_data_stream *stream)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < stream->urbs_submitted; i++) {
|
||||
dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i);
|
||||
/* stop the URB */
|
||||
usb_kill_urb(stream->urb_list[i]);
|
||||
}
|
||||
stream->urbs_submitted = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_urb_submitv2(struct usb_data_stream *stream,
|
||||
struct usb_data_stream_properties *props)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
if (props) {
|
||||
ret = usb_urb_reconfig(stream, props);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < stream->urbs_initialized; i++) {
|
||||
dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i);
|
||||
ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC);
|
||||
if (ret) {
|
||||
dev_err(&stream->udev->dev,
|
||||
"%s: could not submit urb no. %d - get them all back\n",
|
||||
KBUILD_MODNAME, i);
|
||||
usb_urb_killv2(stream);
|
||||
return ret;
|
||||
}
|
||||
stream->urbs_submitted++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_urb_free_urbs(struct usb_data_stream *stream)
|
||||
{
|
||||
int i;
|
||||
|
||||
usb_urb_killv2(stream);
|
||||
|
||||
for (i = stream->urbs_initialized - 1; i >= 0; i--) {
|
||||
if (stream->urb_list[i]) {
|
||||
dev_dbg(&stream->udev->dev, "%s: free urb=%d\n",
|
||||
__func__, i);
|
||||
/* free the URBs */
|
||||
usb_free_urb(stream->urb_list[i]);
|
||||
}
|
||||
}
|
||||
stream->urbs_initialized = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/* allocate the URBs */
|
||||
for (i = 0; i < stream->props.count; i++) {
|
||||
dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
|
||||
stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!stream->urb_list[i]) {
|
||||
dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
|
||||
for (j = 0; j < i; j++)
|
||||
usb_free_urb(stream->urb_list[j]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
usb_fill_bulk_urb(stream->urb_list[i],
|
||||
stream->udev,
|
||||
usb_rcvbulkpipe(stream->udev,
|
||||
stream->props.endpoint),
|
||||
stream->buf_list[i],
|
||||
stream->props.u.bulk.buffersize,
|
||||
usb_urb_complete, stream);
|
||||
|
||||
stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
|
||||
stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
|
||||
stream->urbs_initialized++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/* allocate the URBs */
|
||||
for (i = 0; i < stream->props.count; i++) {
|
||||
struct urb *urb;
|
||||
int frame_offset = 0;
|
||||
dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
|
||||
stream->urb_list[i] = usb_alloc_urb(
|
||||
stream->props.u.isoc.framesperurb, GFP_ATOMIC);
|
||||
if (!stream->urb_list[i]) {
|
||||
dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
|
||||
for (j = 0; j < i; j++)
|
||||
usb_free_urb(stream->urb_list[j]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
urb = stream->urb_list[i];
|
||||
|
||||
urb->dev = stream->udev;
|
||||
urb->context = stream;
|
||||
urb->complete = usb_urb_complete;
|
||||
urb->pipe = usb_rcvisocpipe(stream->udev,
|
||||
stream->props.endpoint);
|
||||
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
|
||||
urb->interval = stream->props.u.isoc.interval;
|
||||
urb->number_of_packets = stream->props.u.isoc.framesperurb;
|
||||
urb->transfer_buffer_length = stream->props.u.isoc.framesize *
|
||||
stream->props.u.isoc.framesperurb;
|
||||
urb->transfer_buffer = stream->buf_list[i];
|
||||
urb->transfer_dma = stream->dma_addr[i];
|
||||
|
||||
for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
|
||||
urb->iso_frame_desc[j].offset = frame_offset;
|
||||
urb->iso_frame_desc[j].length =
|
||||
stream->props.u.isoc.framesize;
|
||||
frame_offset += stream->props.u.isoc.framesize;
|
||||
}
|
||||
|
||||
stream->urbs_initialized++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_free_stream_buffers(struct usb_data_stream *stream)
|
||||
{
|
||||
if (stream->state & USB_STATE_URB_BUF) {
|
||||
while (stream->buf_num) {
|
||||
stream->buf_num--;
|
||||
dev_dbg(&stream->udev->dev, "%s: free buf=%d\n",
|
||||
__func__, stream->buf_num);
|
||||
usb_free_coherent(stream->udev, stream->buf_size,
|
||||
stream->buf_list[stream->buf_num],
|
||||
stream->dma_addr[stream->buf_num]);
|
||||
}
|
||||
}
|
||||
|
||||
stream->state &= ~USB_STATE_URB_BUF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num,
|
||||
unsigned long size)
|
||||
{
|
||||
stream->buf_num = 0;
|
||||
stream->buf_size = size;
|
||||
|
||||
dev_dbg(&stream->udev->dev,
|
||||
"%s: all in all I will use %lu bytes for streaming\n",
|
||||
__func__, num * size);
|
||||
|
||||
for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
|
||||
stream->buf_list[stream->buf_num] = usb_alloc_coherent(
|
||||
stream->udev, size, GFP_ATOMIC,
|
||||
&stream->dma_addr[stream->buf_num]);
|
||||
if (!stream->buf_list[stream->buf_num]) {
|
||||
dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n",
|
||||
__func__, stream->buf_num);
|
||||
usb_free_stream_buffers(stream);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
|
||||
__func__, stream->buf_num,
|
||||
stream->buf_list[stream->buf_num],
|
||||
(long long)stream->dma_addr[stream->buf_num]);
|
||||
memset(stream->buf_list[stream->buf_num], 0, size);
|
||||
stream->state |= USB_STATE_URB_BUF;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_urb_reconfig(struct usb_data_stream *stream,
|
||||
struct usb_data_stream_properties *props)
|
||||
{
|
||||
int buf_size;
|
||||
|
||||
if (!props)
|
||||
return 0;
|
||||
|
||||
/* check allocated buffers are large enough for the request */
|
||||
if (props->type == USB_BULK) {
|
||||
buf_size = stream->props.u.bulk.buffersize;
|
||||
} else if (props->type == USB_ISOC) {
|
||||
buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb;
|
||||
} else {
|
||||
dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n",
|
||||
KBUILD_MODNAME, props->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (stream->buf_num < props->count || stream->buf_size < buf_size) {
|
||||
dev_err(&stream->udev->dev,
|
||||
"%s: cannot reconfigure as allocated buffers are too small\n",
|
||||
KBUILD_MODNAME);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* check if all fields are same */
|
||||
if (stream->props.type == props->type &&
|
||||
stream->props.count == props->count &&
|
||||
stream->props.endpoint == props->endpoint) {
|
||||
if (props->type == USB_BULK &&
|
||||
props->u.bulk.buffersize ==
|
||||
stream->props.u.bulk.buffersize)
|
||||
return 0;
|
||||
else if (props->type == USB_ISOC &&
|
||||
props->u.isoc.framesperurb ==
|
||||
stream->props.u.isoc.framesperurb &&
|
||||
props->u.isoc.framesize ==
|
||||
stream->props.u.isoc.framesize &&
|
||||
props->u.isoc.interval ==
|
||||
stream->props.u.isoc.interval)
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__);
|
||||
|
||||
usb_urb_free_urbs(stream);
|
||||
memcpy(&stream->props, props, sizeof(*props));
|
||||
if (props->type == USB_BULK)
|
||||
return usb_urb_alloc_bulk_urbs(stream);
|
||||
else if (props->type == USB_ISOC)
|
||||
return usb_urb_alloc_isoc_urbs(stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_urb_initv2(struct usb_data_stream *stream,
|
||||
const struct usb_data_stream_properties *props)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!stream || !props)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(&stream->props, props, sizeof(*props));
|
||||
|
||||
if (!stream->complete) {
|
||||
dev_err(&stream->udev->dev,
|
||||
"%s: there is no data callback - this doesn't make sense\n",
|
||||
KBUILD_MODNAME);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (stream->props.type) {
|
||||
case USB_BULK:
|
||||
ret = usb_alloc_stream_buffers(stream, stream->props.count,
|
||||
stream->props.u.bulk.buffersize);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return usb_urb_alloc_bulk_urbs(stream);
|
||||
case USB_ISOC:
|
||||
ret = usb_alloc_stream_buffers(stream, stream->props.count,
|
||||
stream->props.u.isoc.framesize *
|
||||
stream->props.u.isoc.framesperurb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return usb_urb_alloc_isoc_urbs(stream);
|
||||
default:
|
||||
dev_err(&stream->udev->dev,
|
||||
"%s: unknown urb-type for data transfer\n",
|
||||
KBUILD_MODNAME);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int usb_urb_exitv2(struct usb_data_stream *stream)
|
||||
{
|
||||
usb_urb_free_urbs(stream);
|
||||
usb_free_stream_buffers(stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue