2009-03-25 16:59:45 -03:00
/*
2012-06-13 23:33:16 -03:00
* Intel CE6230 DVB USB driver
2009-03-25 16:59:45 -03:00
*
* 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 0213 9 , USA .
*
*/
# include "ce6230.h"
DVB_DEFINE_MOD_OPT_ADAPTER_NR ( adapter_nr ) ;
2012-06-13 23:33:16 -03:00
static int ce6230_ctrl_msg ( struct dvb_usb_device * d , struct usb_req * req )
2009-03-25 16:59:45 -03:00
{
int ret ;
unsigned int pipe ;
u8 request ;
u8 requesttype ;
u16 value ;
u16 index ;
2011-03-20 18:50:49 -03:00
u8 * buf ;
2009-03-25 16:59:45 -03:00
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 :
2012-09-12 20:23:57 -03:00
dev_err ( & d - > udev - > dev , " %s: unknown command=%02x \n " ,
KBUILD_MODNAME , req - > cmd ) ;
2012-06-13 23:33:16 -03:00
ret = - EINVAL ;
2009-03-25 16:59:45 -03:00
goto error ;
}
2011-03-20 18:50:49 -03:00
buf = kmalloc ( req - > data_len , GFP_KERNEL ) ;
if ( ! buf ) {
ret = - ENOMEM ;
goto error ;
}
2009-03-25 16:59:45 -03:00
if ( requesttype = = ( USB_TYPE_VENDOR | USB_DIR_OUT ) ) {
/* write */
memcpy ( buf , req - > data , req - > data_len ) ;
2012-06-13 23:03:08 -03:00
pipe = usb_sndctrlpipe ( d - > udev , 0 ) ;
2009-03-25 16:59:45 -03:00
} else {
/* read */
2012-06-13 23:03:08 -03:00
pipe = usb_rcvctrlpipe ( d - > udev , 0 ) ;
2009-03-25 16:59:45 -03:00
}
msleep ( 1 ) ; /* avoid I2C errors */
2012-06-13 23:03:08 -03:00
ret = usb_control_msg ( d - > udev , pipe , request , requesttype , value , index ,
2012-06-13 23:33:16 -03:00
buf , req - > data_len , CE6230_USB_TIMEOUT ) ;
2009-03-25 16:59:45 -03:00
2012-08-22 19:42:00 -03:00
dvb_usb_dbg_usb_control_msg ( d - > udev , request , requesttype , value , index ,
buf , req - > data_len ) ;
2009-03-25 16:59:45 -03:00
if ( ret < 0 )
2012-09-12 20:23:57 -03:00
dev_err ( & d - > udev - > dev , " %s: usb_control_msg() failed=%d \n " ,
KBUILD_MODNAME , ret ) ;
2009-03-25 16:59:45 -03:00
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 ) ;
2011-03-20 18:50:49 -03:00
kfree ( buf ) ;
2009-03-25 16:59:45 -03:00
error :
return ret ;
}
/* I2C */
2012-06-13 23:33:16 -03:00
static struct zl10353_config ce6230_zl10353_config ;
static int ce6230_i2c_master_xfer ( struct i2c_adapter * adap ,
struct i2c_msg msg [ ] , int num )
2009-03-25 16:59:45 -03:00
{
struct dvb_usb_device * d = i2c_get_adapdata ( adap ) ;
2012-06-13 23:33:16 -03:00
int ret = 0 , i = 0 ;
struct usb_req req ;
2009-03-25 16:59:45 -03:00
if ( num > 2 )
2012-06-13 23:33:16 -03:00
return - EOPNOTSUPP ;
memset ( & req , 0 , sizeof ( req ) ) ;
2009-03-25 16:59:45 -03:00
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 {
2012-09-12 20:23:57 -03:00
dev_err ( & d - > udev - > dev , " %s: I2C read not " \
" implemented \n " ,
2012-06-13 23:33:16 -03:00
KBUILD_MODNAME ) ;
ret = - EOPNOTSUPP ;
2009-03-25 16:59:45 -03:00
}
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 ;
}
2012-06-13 23:33:16 -03:00
static u32 ce6230_i2c_functionality ( struct i2c_adapter * adapter )
2009-03-25 16:59:45 -03:00
{
return I2C_FUNC_I2C ;
}
2012-06-13 23:33:16 -03:00
static struct i2c_algorithm ce6230_i2c_algorithm = {
. master_xfer = ce6230_i2c_master_xfer ,
. functionality = ce6230_i2c_functionality ,
2009-03-25 16:59:45 -03:00
} ;
/* 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 )
{
2012-09-12 20:23:57 -03:00
struct dvb_usb_device * d = adap_to_d ( adap ) ;
dev_dbg ( & d - > udev - > dev , " %s: \n " , __func__ ) ;
2012-06-13 23:33:16 -03:00
2012-06-13 23:03:08 -03:00
adap - > fe [ 0 ] = dvb_attach ( zl10353_attach , & ce6230_zl10353_config ,
2012-09-12 20:23:57 -03:00
& d - > i2c_adap ) ;
2012-06-13 23:03:08 -03:00
if ( adap - > fe [ 0 ] = = NULL )
2009-03-25 16:59:45 -03:00
return - ENODEV ;
2012-06-13 23:33:16 -03:00
2009-03-25 16:59:45 -03:00
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 )
{
2012-09-12 20:23:57 -03:00
struct dvb_usb_device * d = adap_to_d ( adap ) ;
2009-03-25 16:59:45 -03:00
int ret ;
2012-06-13 23:33:16 -03:00
2012-09-12 20:23:57 -03:00
dev_dbg ( & d - > udev - > dev , " %s: \n " , __func__ ) ;
2012-06-13 23:33:16 -03:00
2012-09-12 20:23:57 -03:00
ret = dvb_attach ( mxl5005s_attach , adap - > fe [ 0 ] , & d - > i2c_adap ,
2009-03-25 16:59:45 -03:00
& ce6230_mxl5003s_config ) = = NULL ? - ENODEV : 0 ;
return ret ;
}
static int ce6230_power_ctrl ( struct dvb_usb_device * d , int onoff )
{
int ret ;
2012-06-13 23:33:16 -03:00
2012-09-12 20:23:57 -03:00
dev_dbg ( & d - > udev - > dev , " %s: onoff=%d \n " , __func__ , onoff ) ;
2009-03-25 16:59:45 -03:00
/* InterfaceNumber 1 / AlternateSetting 0 idle
InterfaceNumber 1 / AlternateSetting 1 streaming */
ret = usb_set_interface ( d - > udev , 1 , onoff ) ;
if ( ret )
2012-09-12 20:23:57 -03:00
dev_err ( & d - > udev - > dev , " %s: usb_set_interface() failed=%d \n " ,
KBUILD_MODNAME , ret ) ;
2009-03-25 16:59:45 -03:00
return ret ;
}
/* DVB USB Driver stuff */
2012-06-13 23:03:08 -03:00
static struct dvb_usb_device_properties ce6230_props = {
. driver_name = KBUILD_MODNAME ,
. owner = THIS_MODULE ,
. adapter_nr = adapter_nr ,
. bInterfaceNumber = 1 ,
2009-03-25 16:59:45 -03:00
2012-06-13 23:33:16 -03:00
. i2c_algo = & ce6230_i2c_algorithm ,
2012-06-13 23:03:08 -03:00
. power_ctrl = ce6230_power_ctrl ,
. frontend_attach = ce6230_zl10353_frontend_attach ,
. tuner_attach = ce6230_mxl5003s_tuner_attach ,
2009-03-25 16:59:45 -03:00
. num_adapters = 1 ,
. adapter = {
{
. stream = {
. type = USB_BULK ,
. count = 6 ,
. endpoint = 0x82 ,
. u = {
. bulk = {
2012-06-18 19:50:16 -03:00
. buffersize = ( 16 * 512 ) ,
2009-03-25 16:59:45 -03:00
}
}
} ,
}
} ,
} ;
2012-06-13 23:03:08 -03:00
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 ,
2012-08-14 22:21:09 -03:00
. reset_resume = dvb_usbv2_reset_resume ,
2012-06-13 23:03:08 -03:00
. no_dynamic_id = 1 ,
. soft_unbind = 1 ,
2009-03-25 16:59:45 -03:00
} ;
2012-06-13 23:03:08 -03:00
module_usb_driver ( ce6230_usb_driver ) ;
2009-03-25 16:59:45 -03:00
MODULE_AUTHOR ( " Antti Palosaari <crope@iki.fi> " ) ;
2012-06-13 23:33:16 -03:00
MODULE_DESCRIPTION ( " Intel CE6230 driver " ) ;
2009-03-25 16:59:45 -03:00
MODULE_LICENSE ( " GPL " ) ;