2015-08-05 17:22:42 +02:00
/*
* ddbridge - core . c : Digital Devices bridge core functions
*
2016-05-02 16:27:32 +02:00
* Copyright ( C ) 2010 - 2016 Digital Devices GmbH
2015-08-05 17:22:42 +02:00
* Marcus Metzler < mocm @ metzlerbros . de >
* Ralph Metzler < rjkm @ metzlerbros . de >
2016-03-24 12:10:20 +01:00
*
2015-08-05 17:22:42 +02:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* version 2 only , as published by the Free Software Foundation .
*
*
* 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
* Or , point your browser to http : //www.gnu.org/copyleft/gpl.html
*/
2017-07-10 18:02:59 +02:00
# include <linux/module.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/poll.h>
# include <linux/io.h>
# include <linux/pci.h>
# include <linux/pci_ids.h>
# include <linux/timer.h>
# include <linux/i2c.h>
# include <linux/swab.h>
# include <linux/vmalloc.h>
# include "ddbridge.h"
# include "ddbridge-regs.h"
2017-07-10 19:53:25 +02:00
# include "ddbridge-hw.h"
2017-07-10 20:46:45 +02:00
# include "ddbridge-io.h"
2017-07-10 18:02:59 +02:00
# include "tda18271c2dd.h"
# include "stv6110x.h"
# include "stv090x.h"
# include "lnbh24.h"
# include "drxk.h"
# include "stv0367dd.h"
# include "tda18212dd.h"
# include "cxd2843.h"
# include "cxd2099.h"
# include "stv0910.h"
# include "stv6111.h"
# include "lnbh25.h"
# include "mxl5xx.h"
2015-08-05 17:22:42 +02:00
DEFINE_MUTEX ( redirect_lock ) ;
2016-09-05 14:25:05 +02:00
static int ci_bitrate = 70000 ;
2015-08-05 17:22:42 +02:00
module_param ( ci_bitrate , int , 0444 ) ;
2016-06-27 23:01:21 +02:00
MODULE_PARM_DESC ( ci_bitrate , " Bitrate in KHz for output to CI. " ) ;
2015-08-05 17:22:42 +02:00
static int ts_loop = - 1 ;
module_param ( ts_loop , int , 0444 ) ;
MODULE_PARM_DESC ( ts_loop , " TS in/out test loop on port ts_loop " ) ;
static int vlan ;
module_param ( vlan , int , 0444 ) ;
MODULE_PARM_DESC ( vlan , " VLAN and QoS IDs enabled " ) ;
static int tt ;
module_param ( tt , int , 0444 ) ;
MODULE_PARM_DESC ( tt , " " ) ;
static int fmode ;
module_param ( fmode , int , 0444 ) ;
MODULE_PARM_DESC ( fmode , " frontend emulation mode " ) ;
2017-04-07 22:21:06 +02:00
static int fmode_sat = - 1 ;
module_param ( fmode_sat , int , 0444 ) ;
MODULE_PARM_DESC ( fmode_sat , " set frontend emulation mode sat " ) ;
2015-08-05 17:22:42 +02:00
static int old_quattro ;
module_param ( old_quattro , int , 0444 ) ;
MODULE_PARM_DESC ( old_quattro , " old quattro LNB input order " ) ;
2016-04-12 12:18:09 +02:00
static int xo2_speed = 2 ;
module_param ( xo2_speed , int , 0444 ) ;
MODULE_PARM_DESC ( xo2_speed , " default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards " ) ;
2016-05-02 16:27:32 +02:00
# ifdef __arm__
2016-04-15 22:45:55 +02:00
static int alt_dma = 1 ;
# else
static int alt_dma ;
# endif
2016-04-15 18:08:51 +02:00
module_param ( alt_dma , int , 0444 ) ;
MODULE_PARM_DESC ( alt_dma , " use alternative DMA buffer handling " ) ;
2016-04-15 22:45:55 +02:00
static int no_init ;
module_param ( no_init , int , 0444 ) ;
MODULE_PARM_DESC ( no_init , " do not initialize most devices " ) ;
2016-12-30 15:03:38 +01:00
static int stv0910_single ;
module_param ( stv0910_single , int , 0444 ) ;
MODULE_PARM_DESC ( no_init , " use stv0910 cards as single demods " ) ;
2015-08-05 17:22:42 +02:00
# define DDB_MAX_ADAPTER 64
static struct ddb * ddbs [ DDB_MAX_ADAPTER ] ;
DVB_DEFINE_MOD_OPT_ADAPTER_NR ( adapter_nr ) ;
2016-05-02 16:27:32 +02:00
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static void ddb_set_dma_table ( struct ddb_io * io )
2015-08-05 17:22:42 +02:00
{
2016-05-02 16:27:32 +02:00
struct ddb * dev = io - > port - > dev ;
struct ddb_dma * dma = io - > dma ;
u32 i ;
2015-08-05 17:22:42 +02:00
u64 mem ;
if ( ! dma )
return ;
for ( i = 0 ; i < dma - > num ; i + + ) {
mem = dma - > pbuf [ i ] ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , mem & 0xffffffff , dma - > bufregs + i * 8 ) ;
ddbwritel ( dev , mem > > 32 , dma - > bufregs + i * 8 + 4 ) ;
2015-08-05 17:22:42 +02:00
}
2017-02-21 17:12:35 +01:00
dma - > bufval = ( ( dma - > div & 0x0f ) < < 16 ) |
2015-08-05 17:22:42 +02:00
( ( dma - > num & 0x1f ) < < 11 ) |
( ( dma - > size > > 7 ) & 0x7ff ) ;
}
static void ddb_set_dma_tables ( struct ddb * dev )
{
u32 i ;
2017-04-16 21:20:52 +02:00
2016-05-02 16:27:32 +02:00
for ( i = 0 ; i < DDB_MAX_PORT ; i + + ) {
if ( dev - > port [ i ] . input [ 0 ] )
ddb_set_dma_table ( dev - > port [ i ] . input [ 0 ] ) ;
if ( dev - > port [ i ] . input [ 1 ] )
ddb_set_dma_table ( dev - > port [ i ] . input [ 1 ] ) ;
if ( dev - > port [ i ] . output )
ddb_set_dma_table ( dev - > port [ i ] . output ) ;
2017-04-16 21:20:52 +02:00
}
2015-08-05 17:22:42 +02:00
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static void ddb_redirect_dma ( struct ddb * dev ,
struct ddb_dma * sdma ,
struct ddb_dma * ddma )
{
u32 i , base ;
u64 mem ;
2016-04-20 16:27:56 +02:00
sdma - > bufval = ddma - > bufval ;
2016-05-02 16:27:32 +02:00
base = sdma - > bufregs ;
2015-08-05 17:22:42 +02:00
for ( i = 0 ; i < ddma - > num ; i + + ) {
mem = ddma - > pbuf [ i ] ;
ddbwritel ( dev , mem & 0xffffffff , base + i * 8 ) ;
ddbwritel ( dev , mem > > 32 , base + i * 8 + 4 ) ;
}
}
static int ddb_unredirect ( struct ddb_port * port )
{
struct ddb_input * oredi , * iredi = 0 ;
struct ddb_output * iredo = 0 ;
2016-10-10 00:19:16 +02:00
/*pr_info("DDBridge: unredirect %d.%d\n", port->dev->nr, port->nr);*/
2015-08-05 17:22:42 +02:00
mutex_lock ( & redirect_lock ) ;
if ( port - > output - > dma - > running ) {
mutex_unlock ( & redirect_lock ) ;
return - EBUSY ;
}
oredi = port - > output - > redi ;
if ( ! oredi )
goto done ;
if ( port - > input [ 0 ] ) {
iredi = port - > input [ 0 ] - > redi ;
iredo = port - > input [ 0 ] - > redo ;
if ( iredo ) {
iredo - > port - > output - > redi = oredi ;
if ( iredo - > port - > input [ 0 ] ) {
iredo - > port - > input [ 0 ] - > redi = iredi ;
ddb_redirect_dma ( oredi - > port - > dev ,
oredi - > dma , iredo - > dma ) ;
}
port - > input [ 0 ] - > redo = 0 ;
2016-05-02 16:27:32 +02:00
ddb_set_dma_table ( port - > input [ 0 ] ) ;
2015-08-05 17:22:42 +02:00
}
oredi - > redi = iredi ;
port - > input [ 0 ] - > redi = 0 ;
}
oredi - > redo = 0 ;
port - > output - > redi = 0 ;
2016-05-02 16:27:32 +02:00
ddb_set_dma_table ( oredi ) ;
2015-08-05 17:22:42 +02:00
done :
mutex_unlock ( & redirect_lock ) ;
return 0 ;
}
static int ddb_redirect ( u32 i , u32 p )
{
2016-05-31 16:53:04 +02:00
struct ddb * idev = ddbs [ ( i > > 4 ) & 0x3f ] ;
2015-08-05 17:22:42 +02:00
struct ddb_input * input , * input2 ;
2016-05-31 16:53:04 +02:00
struct ddb * pdev = ddbs [ ( p > > 4 ) & 0x3f ] ;
2015-08-05 17:22:42 +02:00
struct ddb_port * port ;
if ( ! idev - > has_dma | | ! pdev - > has_dma )
return - EINVAL ;
if ( ! idev | | ! pdev )
return - EINVAL ;
port = & pdev - > port [ p & 0x0f ] ;
if ( ! port - > output )
return - EINVAL ;
if ( ddb_unredirect ( port ) )
return - EBUSY ;
if ( i = = 8 )
return 0 ;
input = & idev - > input [ i & 7 ] ;
if ( ! input )
return - EINVAL ;
mutex_lock ( & redirect_lock ) ;
if ( port - > output - > dma - > running | | input - > dma - > running ) {
mutex_unlock ( & redirect_lock ) ;
return - EBUSY ;
}
input2 = port - > input [ 0 ] ;
if ( input2 ) {
if ( input - > redi ) {
input2 - > redi = input - > redi ;
input - > redi = 0 ;
} else
input2 - > redi = input ;
}
input - > redo = port - > output ;
port - > output - > redi = input ;
ddb_redirect_dma ( input - > port - > dev , input - > dma , port - > output - > dma ) ;
mutex_unlock ( & redirect_lock ) ;
return 0 ;
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static void dma_free ( struct pci_dev * pdev , struct ddb_dma * dma , int dir )
{
int i ;
if ( ! dma )
return ;
for ( i = 0 ; i < dma - > num ; i + + ) {
if ( dma - > vbuf [ i ] ) {
2016-04-15 18:08:51 +02:00
if ( alt_dma ) {
dma_unmap_single ( & pdev - > dev , dma - > pbuf [ i ] ,
dma - > size ,
dir ? DMA_TO_DEVICE :
DMA_FROM_DEVICE ) ;
kfree ( dma - > vbuf [ i ] ) ;
} else
dma_free_coherent ( & pdev - > dev , dma - > size ,
dma - > vbuf [ i ] ,
dma - > pbuf [ i ] ) ;
2015-08-05 17:22:42 +02:00
dma - > vbuf [ i ] = 0 ;
}
}
}
static int dma_alloc ( struct pci_dev * pdev , struct ddb_dma * dma , int dir )
{
int i ;
if ( ! dma )
return 0 ;
for ( i = 0 ; i < dma - > num ; i + + ) {
2016-04-15 18:08:51 +02:00
if ( alt_dma ) {
dma - > vbuf [ i ] = kmalloc ( dma - > size , __GFP_REPEAT ) ;
if ( ! dma - > vbuf [ i ] )
return - ENOMEM ;
dma - > pbuf [ i ] = dma_map_single ( & pdev - > dev ,
dma - > vbuf [ i ] ,
dma - > size ,
dir ? DMA_TO_DEVICE :
DMA_FROM_DEVICE ) ;
if ( dma_mapping_error ( & pdev - > dev , dma - > pbuf [ i ] ) ) {
kfree ( dma - > vbuf [ i ] ) ;
2016-04-15 23:53:20 +02:00
dma - > vbuf [ i ] = 0 ;
2016-04-15 18:08:51 +02:00
return - ENOMEM ;
}
} else {
dma - > vbuf [ i ] = dma_alloc_coherent ( & pdev - > dev ,
dma - > size ,
& dma - > pbuf [ i ] ,
GFP_KERNEL ) ;
if ( ! dma - > vbuf [ i ] )
return - ENOMEM ;
}
2015-08-05 17:22:42 +02:00
}
return 0 ;
}
2017-07-10 18:02:59 +02:00
int ddb_buffers_alloc ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
int i ;
struct ddb_port * port ;
2016-05-05 00:15:02 +02:00
for ( i = 0 ; i < dev - > port_num ; i + + ) {
2015-08-05 17:22:42 +02:00
port = & dev - > port [ i ] ;
switch ( port - > class ) {
case DDB_PORT_TUNER :
if ( port - > input [ 0 ] - > dma )
2016-03-24 12:10:20 +01:00
if ( dma_alloc ( dev - > pdev ,
port - > input [ 0 ] - > dma , 0 ) < 0 )
2015-08-05 17:22:42 +02:00
return - 1 ;
if ( port - > input [ 1 ] - > dma )
2016-03-24 12:10:20 +01:00
if ( dma_alloc ( dev - > pdev ,
port - > input [ 1 ] - > dma , 0 ) < 0 )
2015-08-05 17:22:42 +02:00
return - 1 ;
break ;
case DDB_PORT_CI :
case DDB_PORT_LOOP :
if ( port - > input [ 0 ] - > dma )
2016-03-24 12:10:20 +01:00
if ( dma_alloc ( dev - > pdev ,
port - > input [ 0 ] - > dma , 0 ) < 0 )
2015-08-05 17:22:42 +02:00
return - 1 ;
case DDB_PORT_MOD :
if ( port - > output - > dma )
2016-03-24 12:10:20 +01:00
if ( dma_alloc ( dev - > pdev ,
port - > output - > dma , 1 ) < 0 )
2015-08-05 17:22:42 +02:00
return - 1 ;
break ;
default :
break ;
}
}
ddb_set_dma_tables ( dev ) ;
return 0 ;
}
2017-07-10 18:02:59 +02:00
void ddb_buffers_free ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
int i ;
struct ddb_port * port ;
2016-05-05 00:15:02 +02:00
for ( i = 0 ; i < dev - > port_num ; i + + ) {
2015-08-05 17:22:42 +02:00
port = & dev - > port [ i ] ;
if ( port - > input [ 0 ] & & port - > input [ 0 ] - > dma )
dma_free ( dev - > pdev , port - > input [ 0 ] - > dma , 0 ) ;
if ( port - > input [ 1 ] & & port - > input [ 1 ] - > dma )
dma_free ( dev - > pdev , port - > input [ 1 ] - > dma , 0 ) ;
if ( port - > output & & port - > output - > dma )
dma_free ( dev - > pdev , port - > output - > dma , 1 ) ;
}
}
2016-10-24 15:13:26 +02:00
/*
2017-04-16 21:20:52 +02:00
* Control :
*
* Bit 0 - Enable TS
* 1 - Reset
* 2 - clock enable
* 3 - clock phase
* 4 - gap enable
* 5 - send null packets on underrun
* 6 - enable clock gating
* 7 - set error bit on inserted null packets
* 8 - 10 - fine adjust clock delay
* 11 - HS ( high speed ) , if NCO mode = 0 : 0 = 72 MHz 1 = 96 Mhz
* 12 - enable NCO mode
*
* Control 2 :
*
* Bit 0 - 6 : gap_size , Gap = ( gap_size * 2 ) + 4
* 16 - 31 : HS = 0 : Speed = 72 * Value / 8192 MBit / s
* HS = 1 : Speed = 72 * 8 / ( Value + 1 ) MBit / s ( only bit 19 - 16 used )
*
*/
2016-10-24 15:13:26 +02:00
2016-06-27 23:01:21 +02:00
static void calc_con ( struct ddb_output * output , u32 * con , u32 * con2 , u32 flags )
2016-06-16 15:40:24 +02:00
{
struct ddb * dev = output - > port - > dev ;
2016-06-27 23:01:21 +02:00
u32 bitrate = output - > port - > obr , max_bitrate = 72000 ;
u32 gap = 4 , nco = 0 ;
2017-04-16 21:20:52 +02:00
* con = 0x1C ;
2016-06-27 23:01:21 +02:00
if ( output - > port - > gap ! = 0xffffffff ) {
flags | = 1 ;
gap = output - > port - > gap ;
}
2016-06-16 15:40:24 +02:00
if ( dev - > link [ 0 ] . info - > type = = DDB_OCTOPUS_CI & & output - > port - > nr > 1 ) {
2016-06-27 23:01:21 +02:00
* con = 0x10c ;
if ( dev - > link [ 0 ] . ids . regmapid > = 0x10003 & & ! ( flags & 1 ) ) {
if ( ! ( flags & 2 ) ) {
/* NCO */
max_bitrate = 0 ;
2016-06-16 15:40:24 +02:00
gap = 0 ;
2016-06-27 23:01:21 +02:00
if ( bitrate ! = 72000 ) {
2016-06-16 15:40:24 +02:00
if ( bitrate > = 96000 )
2016-06-27 23:01:21 +02:00
* con | = 0x800 ;
else {
* con | = 0x1000 ;
2017-04-16 21:20:52 +02:00
nco = ( bitrate *
8192 + 71999 ) / 72000 ;
2016-06-27 23:01:21 +02:00
}
2016-06-16 15:40:24 +02:00
}
} else {
2016-06-27 23:01:21 +02:00
/* Divider and gap */
* con | = 0x1810 ;
2016-06-16 15:40:24 +02:00
if ( bitrate < = 64000 ) {
2016-06-27 23:01:21 +02:00
max_bitrate = 64000 ;
nco = 8 ;
2017-04-16 21:20:52 +02:00
} else if ( bitrate < = 72000 ) {
2016-06-27 23:01:21 +02:00
max_bitrate = 72000 ;
nco = 7 ;
2016-06-16 15:40:24 +02:00
} else {
2016-06-27 23:01:21 +02:00
max_bitrate = 96000 ;
nco = 5 ;
2016-06-16 15:40:24 +02:00
}
}
} else {
if ( bitrate > 72000 ) {
2016-06-27 23:01:21 +02:00
* con | = 0x810 ; /* 96 MBit/s and gap */
max_bitrate = 96000 ;
2016-06-16 15:40:24 +02:00
}
}
}
2016-06-27 23:01:21 +02:00
if ( max_bitrate > 0 ) {
if ( bitrate > max_bitrate )
bitrate = max_bitrate ;
2016-06-16 15:40:24 +02:00
if ( bitrate < 31000 )
bitrate = 31000 ;
2016-06-27 23:01:21 +02:00
gap = ( ( max_bitrate - bitrate ) * 94 ) / bitrate ;
2016-06-16 15:40:24 +02:00
if ( gap < 2 )
2016-06-27 23:01:21 +02:00
* con & = ~ 0x10 ; /* Disable gap */
2016-06-16 15:40:24 +02:00
else
gap - = 2 ;
if ( gap > 127 )
gap = 127 ;
}
2016-06-27 23:01:21 +02:00
* con2 = ( nco < < 16 ) | gap ;
2016-06-16 15:40:24 +02:00
}
2015-08-05 17:22:42 +02:00
static void ddb_output_start ( struct ddb_output * output )
{
struct ddb * dev = output - > port - > dev ;
2016-06-27 23:01:21 +02:00
u32 con = 0x11c , con2 = 0 ;
2015-08-05 17:22:42 +02:00
2017-04-16 21:20:52 +02:00
pr_info ( " Channel Base = %08x \n " , output - > regs ) ;
2015-08-05 17:22:42 +02:00
if ( output - > dma ) {
spin_lock_irq ( & output - > dma - > lock ) ;
output - > dma - > cbuf = 0 ;
output - > dma - > coff = 0 ;
output - > dma - > stat = 0 ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , DMA_BUFFER_CONTROL ( output - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
if ( output - > port - > class = = DDB_PORT_MOD )
ddbridge_mod_output_start ( output ) ;
else {
2016-06-27 23:01:21 +02:00
if ( output - > port - > input [ 0 ] - > port - > class = = DDB_PORT_LOOP )
con = ( 1UL < < 13 ) | 0x14 ;
else
calc_con ( output , & con , & con2 , 0 ) ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , TS_CONTROL ( output ) ) ;
ddbwritel ( dev , 2 , TS_CONTROL ( output ) ) ;
ddbwritel ( dev , 0 , TS_CONTROL ( output ) ) ;
2016-06-27 23:01:21 +02:00
ddbwritel ( dev , con , TS_CONTROL ( output ) ) ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , con2 , TS_CONTROL2 ( output ) ) ;
2015-08-05 17:22:42 +02:00
}
if ( output - > dma ) {
2016-04-20 16:27:56 +02:00
ddbwritel ( dev , output - > dma - > bufval ,
2016-05-02 16:27:32 +02:00
DMA_BUFFER_SIZE ( output - > dma ) ) ;
ddbwritel ( dev , 0 , DMA_BUFFER_ACK ( output - > dma ) ) ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , 1 , DMA_BASE_READ ) ;
2017-05-04 09:09:34 +02:00
ddbwritel ( dev , 7 , DMA_BUFFER_CONTROL ( output - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
2016-06-27 23:01:21 +02:00
if ( output - > port - > class ! = DDB_PORT_MOD )
ddbwritel ( dev , con | 1 , TS_CONTROL ( output ) ) ;
2015-08-05 17:22:42 +02:00
if ( output - > dma ) {
output - > dma - > running = 1 ;
spin_unlock_irq ( & output - > dma - > lock ) ;
}
}
static void ddb_output_stop ( struct ddb_output * output )
{
struct ddb * dev = output - > port - > dev ;
if ( output - > dma )
spin_lock_irq ( & output - > dma - > lock ) ;
if ( output - > port - > class = = DDB_PORT_MOD )
ddbridge_mod_output_stop ( output ) ;
else
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , TS_CONTROL ( output ) ) ;
2015-08-05 17:22:42 +02:00
if ( output - > dma ) {
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , DMA_BUFFER_CONTROL ( output - > dma ) ) ;
2015-08-05 17:22:42 +02:00
output - > dma - > running = 0 ;
spin_unlock_irq ( & output - > dma - > lock ) ;
}
}
static void ddb_input_stop ( struct ddb_input * input )
{
struct ddb * dev = input - > port - > dev ;
u32 tag = DDB_LINK_TAG ( input - > port - > lnr ) ;
if ( input - > dma )
spin_lock_irq ( & input - > dma - > lock ) ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , tag | TS_CONTROL ( input ) ) ;
2015-08-05 17:22:42 +02:00
if ( input - > dma ) {
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , DMA_BUFFER_CONTROL ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
input - > dma - > running = 0 ;
spin_unlock_irq ( & input - > dma - > lock ) ;
}
2016-03-24 12:10:20 +01:00
/*printk("input_stop %u.%u.%u\n",
2017-04-16 21:20:52 +02:00
* dev - > nr , input - > port - > lnr , input - > nr ) ;
*/
2015-08-05 17:22:42 +02:00
}
static void ddb_input_start ( struct ddb_input * input )
{
struct ddb * dev = input - > port - > dev ;
if ( input - > dma ) {
spin_lock_irq ( & input - > dma - > lock ) ;
input - > dma - > cbuf = 0 ;
input - > dma - > coff = 0 ;
input - > dma - > stat = 0 ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , DMA_BUFFER_CONTROL ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , TS_CONTROL ( input ) ) ;
ddbwritel ( dev , 2 , TS_CONTROL ( input ) ) ;
ddbwritel ( dev , 0 , TS_CONTROL ( input ) ) ;
2015-08-05 17:22:42 +02:00
if ( input - > dma ) {
2016-04-20 16:27:56 +02:00
ddbwritel ( dev , input - > dma - > bufval ,
2016-05-02 16:27:32 +02:00
DMA_BUFFER_SIZE ( input - > dma ) ) ;
ddbwritel ( dev , 0 , DMA_BUFFER_ACK ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , 1 , DMA_BASE_WRITE ) ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 3 , DMA_BUFFER_CONTROL ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
if ( dev - > link [ 0 ] . info - > type = = DDB_OCTONET )
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0x01 , TS_CONTROL ( input ) ) ;
2015-08-05 17:22:42 +02:00
else
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0x09 , TS_CONTROL ( input ) ) ;
2015-08-05 17:22:42 +02:00
if ( input - > dma ) {
input - > dma - > running = 1 ;
spin_unlock_irq ( & input - > dma - > lock ) ;
}
}
2017-07-10 18:02:59 +02:00
int ddb_dvb_ns_input_start ( struct ddb_input * input )
2015-08-05 17:22:42 +02:00
{
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
if ( ! dvb - > users )
ddb_input_start ( input ) ;
return + + dvb - > users ;
}
2017-07-10 18:02:59 +02:00
int ddb_dvb_ns_input_stop ( struct ddb_input * input )
2015-08-05 17:22:42 +02:00
{
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
if ( - - dvb - > users )
return dvb - > users ;
ddb_input_stop ( input ) ;
return 0 ;
}
static void ddb_input_start_all ( struct ddb_input * input )
{
struct ddb_input * i = input ;
struct ddb_output * o ;
mutex_lock ( & redirect_lock ) ;
while ( i & & ( o = i - > redo ) ) {
ddb_output_start ( o ) ;
i = o - > port - > input [ 0 ] ;
if ( i )
ddb_input_start ( i ) ;
}
ddb_input_start ( input ) ;
mutex_unlock ( & redirect_lock ) ;
}
static void ddb_input_stop_all ( struct ddb_input * input )
{
struct ddb_input * i = input ;
struct ddb_output * o ;
mutex_lock ( & redirect_lock ) ;
ddb_input_stop ( input ) ;
while ( i & & ( o = i - > redo ) ) {
ddb_output_stop ( o ) ;
i = o - > port - > input [ 0 ] ;
if ( i )
ddb_input_stop ( i ) ;
}
mutex_unlock ( & redirect_lock ) ;
}
static u32 ddb_output_free ( struct ddb_output * output )
{
u32 idx , off , stat = output - > dma - > stat ;
s32 diff ;
idx = ( stat > > 11 ) & 0x1f ;
off = ( stat & 0x7ff ) < < 7 ;
if ( output - > dma - > cbuf ! = idx ) {
if ( ( ( ( output - > dma - > cbuf + 1 ) % output - > dma - > num ) = = idx ) & &
( output - > dma - > size - output - > dma - > coff < = 188 ) )
return 0 ;
return 188 ;
}
diff = off - output - > dma - > coff ;
if ( diff < = 0 | | diff > 188 )
return 188 ;
return 0 ;
}
#if 0
static u32 ddb_dma_free ( struct ddb_dma * dma )
{
u32 idx , off , stat = dma - > stat ;
s32 p1 , p2 , diff ;
idx = ( stat > > 11 ) & 0x1f ;
off = ( stat & 0x7ff ) < < 7 ;
p1 = idx * dma - > size + off ;
p2 = dma - > cbuf * dma - > size + dma - > coff ;
diff = p1 - p2 ;
if ( diff < = 0 )
diff + = dma - > num * dma - > size ;
return diff ;
}
# endif
static ssize_t ddb_output_write ( struct ddb_output * output ,
2015-12-13 22:26:35 +01:00
const __user u8 * buf , size_t count )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = output - > port - > dev ;
u32 idx , off , stat = output - > dma - > stat ;
u32 left = count , len ;
idx = ( stat > > 11 ) & 0x1f ;
off = ( stat & 0x7ff ) < < 7 ;
while ( left ) {
len = output - > dma - > size - output - > dma - > coff ;
if ( ( ( ( output - > dma - > cbuf + 1 ) % output - > dma - > num ) = = idx ) & &
( off = = 0 ) ) {
if ( len < = 188 )
break ;
len - = 188 ;
}
if ( output - > dma - > cbuf = = idx ) {
if ( off > output - > dma - > coff ) {
len = off - output - > dma - > coff ;
len - = ( len % 188 ) ;
if ( len < = 188 )
break ;
len - = 188 ;
}
}
if ( len > left )
len = left ;
if ( copy_from_user ( output - > dma - > vbuf [ output - > dma - > cbuf ] +
output - > dma - > coff ,
buf , len ) )
return - EIO ;
2016-04-15 18:08:51 +02:00
if ( alt_dma )
dma_sync_single_for_device ( dev - > dev ,
output - > dma - > pbuf [
output - > dma - > cbuf ] ,
2017-04-16 21:20:52 +02:00
output - > dma - > size ,
DMA_TO_DEVICE ) ;
2015-08-05 17:22:42 +02:00
left - = len ;
buf + = len ;
output - > dma - > coff + = len ;
if ( output - > dma - > coff = = output - > dma - > size ) {
output - > dma - > coff = 0 ;
output - > dma - > cbuf = ( ( output - > dma - > cbuf + 1 ) %
output - > dma - > num ) ;
}
ddbwritel ( dev ,
( output - > dma - > cbuf < < 11 ) |
( output - > dma - > coff > > 7 ) ,
2016-05-02 16:27:32 +02:00
DMA_BUFFER_ACK ( output - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
return count - left ;
}
#if 0
static u32 ddb_input_free_bytes ( struct ddb_input * input )
{
struct ddb * dev = input - > port - > dev ;
u32 idx , off , stat = input - > dma - > stat ;
2016-05-02 16:27:32 +02:00
u32 ctrl = ddbreadl ( dev , DMA_BUFFER_CONTROL ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
idx = ( stat > > 11 ) & 0x1f ;
off = ( stat & 0x7ff ) < < 7 ;
if ( ctrl & 4 )
return 0 ;
if ( input - > dma - > cbuf ! = idx )
return 1 ;
return 0 ;
}
static s32 ddb_output_used_bufs ( struct ddb_output * output )
{
u32 idx , off , stat , ctrl ;
s32 diff ;
spin_lock_irq ( & output - > dma - > lock ) ;
stat = output - > dma - > stat ;
ctrl = output - > dma - > ctrl ;
spin_unlock_irq ( & output - > dma - > lock ) ;
idx = ( stat > > 11 ) & 0x1f ;
off = ( stat & 0x7ff ) < < 7 ;
if ( ctrl & 4 )
return 0 ;
diff = output - > dma - > cbuf - idx ;
if ( diff = = 0 & & off < output - > dma - > coff )
return 0 ;
if ( diff < = 0 )
diff + = output - > dma - > num ;
return diff ;
}
static s32 ddb_input_free_bufs ( struct ddb_input * input )
{
u32 idx , off , stat , ctrl ;
s32 free ;
spin_lock_irq ( & input - > dma - > lock ) ;
ctrl = input - > dma - > ctrl ;
stat = input - > dma - > stat ;
spin_unlock_irq ( & input - > dma - > lock ) ;
if ( ctrl & 4 )
return 0 ;
idx = ( stat > > 11 ) & 0x1f ;
off = ( stat & 0x7ff ) < < 7 ;
free = input - > dma - > cbuf - idx ;
if ( free = = 0 & & off < input - > dma - > coff )
return 0 ;
if ( free < = 0 )
free + = input - > dma - > num ;
return free - 1 ;
}
static u32 ddb_output_ok ( struct ddb_output * output )
{
struct ddb_input * input = output - > port - > input [ 0 ] ;
s32 diff ;
diff = ddb_input_free_bufs ( input ) - ddb_output_used_bufs ( output ) ;
if ( diff > 0 )
return 1 ;
return 0 ;
}
# endif
static u32 ddb_input_avail ( struct ddb_input * input )
{
struct ddb * dev = input - > port - > dev ;
u32 idx , off , stat = input - > dma - > stat ;
2016-05-02 16:27:32 +02:00
u32 ctrl = ddbreadl ( dev , DMA_BUFFER_CONTROL ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
idx = ( stat > > 11 ) & 0x1f ;
off = ( stat & 0x7ff ) < < 7 ;
if ( ctrl & 4 ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: IA %d %d %08x \n " , idx , off , ctrl ) ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , stat , DMA_BUFFER_ACK ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
return 0 ;
}
if ( input - > dma - > cbuf ! = idx )
return 188 ;
return 0 ;
}
2016-03-24 12:10:20 +01:00
static size_t ddb_input_read ( struct ddb_input * input ,
__user u8 * buf , size_t count )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = input - > port - > dev ;
u32 left = count ;
u32 idx , off , free , stat = input - > dma - > stat ;
int ret ;
idx = ( stat > > 11 ) & 0x1f ;
off = ( stat & 0x7ff ) < < 7 ;
while ( left ) {
if ( input - > dma - > cbuf = = idx )
return count - left ;
free = input - > dma - > size - input - > dma - > coff ;
if ( free > left )
free = left ;
2016-04-15 18:08:51 +02:00
if ( alt_dma )
dma_sync_single_for_cpu ( dev - > dev ,
2017-04-16 21:20:52 +02:00
input - > dma - > pbuf [
input - > dma - > cbuf ] ,
input - > dma - > size ,
DMA_FROM_DEVICE ) ;
2015-08-05 17:22:42 +02:00
ret = copy_to_user ( buf , input - > dma - > vbuf [ input - > dma - > cbuf ] +
input - > dma - > coff , free ) ;
if ( ret )
return - EFAULT ;
input - > dma - > coff + = free ;
if ( input - > dma - > coff = = input - > dma - > size ) {
input - > dma - > coff = 0 ;
input - > dma - > cbuf = ( input - > dma - > cbuf + 1 ) %
input - > dma - > num ;
}
left - = free ;
2016-06-10 09:45:21 +02:00
buf + = free ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev ,
( input - > dma - > cbuf < < 11 ) | ( input - > dma - > coff > > 7 ) ,
2016-05-02 16:27:32 +02:00
DMA_BUFFER_ACK ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
return count ;
}
/****************************************************************************/
/****************************************************************************/
static ssize_t ts_write ( struct file * file , const char * buf ,
size_t count , loff_t * ppos )
{
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
struct ddb * dev = output - > port - > dev ;
size_t left = count ;
int stat ;
if ( ! dev - > has_dma )
return - EINVAL ;
while ( left ) {
if ( ddb_output_free ( output ) < 188 ) {
if ( file - > f_flags & O_NONBLOCK )
break ;
if ( wait_event_interruptible (
output - > dma - > wq ,
ddb_output_free ( output ) > = 188 ) < 0 )
break ;
}
stat = ddb_output_write ( output , buf , left ) ;
if ( stat < 0 )
return stat ;
buf + = stat ;
left - = stat ;
}
return ( left = = count ) ? - EAGAIN : ( count - left ) ;
}
2015-12-13 22:26:35 +01:00
static ssize_t ts_read ( struct file * file , __user char * buf ,
2015-08-05 17:22:42 +02:00
size_t count , loff_t * ppos )
{
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
struct ddb_input * input = output - > port - > input [ 0 ] ;
struct ddb * dev = output - > port - > dev ;
size_t left = count ;
int stat ;
if ( ! dev - > has_dma )
return - EINVAL ;
while ( left ) {
if ( ddb_input_avail ( input ) < 188 ) {
if ( file - > f_flags & O_NONBLOCK )
break ;
if ( wait_event_interruptible (
input - > dma - > wq ,
ddb_input_avail ( input ) > = 188 ) < 0 )
break ;
}
stat = ddb_input_read ( input , buf , left ) ;
if ( stat < 0 )
return stat ;
left - = stat ;
buf + = stat ;
}
return ( count & & ( left = = count ) ) ? - EAGAIN : ( count - left ) ;
}
static unsigned int ts_poll ( struct file * file , poll_table * wait )
{
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
struct ddb_input * input = output - > port - > input [ 0 ] ;
unsigned int mask = 0 ;
poll_wait ( file , & input - > dma - > wq , wait ) ;
poll_wait ( file , & output - > dma - > wq , wait ) ;
if ( ddb_input_avail ( input ) > = 188 )
mask | = POLLIN | POLLRDNORM ;
if ( ddb_output_free ( output ) > = 188 )
mask | = POLLOUT | POLLWRNORM ;
return mask ;
}
static int ts_release ( struct inode * inode , struct file * file )
{
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
struct ddb_input * input = output - > port - > input [ 0 ] ;
if ( ( file - > f_flags & O_ACCMODE ) = = O_RDONLY ) {
if ( ! input )
return - EINVAL ;
ddb_input_stop ( input ) ;
} else if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY ) {
if ( ! output )
return - EINVAL ;
ddb_output_stop ( output ) ;
}
return dvb_generic_release ( inode , file ) ;
}
static int ts_open ( struct inode * inode , struct file * file )
{
int err ;
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
struct ddb_input * input = output - > port - > input [ 0 ] ;
if ( ( file - > f_flags & O_ACCMODE ) = = O_RDONLY ) {
if ( ! input )
return - EINVAL ;
if ( input - > redo | | input - > redi )
return - EBUSY ;
} else if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY ) {
if ( ! output )
return - EINVAL ;
2015-09-24 23:29:09 +02:00
} else
return - EINVAL ;
2015-08-05 17:22:42 +02:00
err = dvb_generic_open ( inode , file ) ;
if ( err < 0 )
return err ;
if ( ( file - > f_flags & O_ACCMODE ) = = O_RDONLY )
ddb_input_start ( input ) ;
else if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY )
ddb_output_start ( output ) ;
return err ;
}
static int mod_release ( struct inode * inode , struct file * file )
{
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY ) {
if ( ! output )
return - EINVAL ;
ddb_output_stop ( output ) ;
}
return dvb_generic_release ( inode , file ) ;
}
static int mod_open ( struct inode * inode , struct file * file )
{
int err ;
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY ) {
if ( ! output )
return - EINVAL ;
}
err = dvb_generic_open ( inode , file ) ;
if ( err < 0 )
return err ;
if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY )
ddb_output_start ( output ) ;
return err ;
}
static const struct file_operations ci_fops = {
. owner = THIS_MODULE ,
. read = ts_read ,
. write = ts_write ,
. open = ts_open ,
. release = ts_release ,
. poll = ts_poll ,
. mmap = 0 ,
} ;
static struct dvb_device dvbdev_ci = {
. priv = 0 ,
. readers = 1 ,
. writers = 1 ,
. users = 2 ,
. fops = & ci_fops ,
} ;
/****************************************************************************/
/****************************************************************************/
static long mod_ioctl ( struct file * file ,
unsigned int cmd , unsigned long arg )
{
return dvb_usercopy ( file , cmd , arg , ddbridge_mod_do_ioctl ) ;
}
static const struct file_operations mod_fops = {
. owner = THIS_MODULE ,
. read = ts_read ,
. write = ts_write ,
. open = mod_open ,
. release = mod_release ,
. poll = ts_poll ,
. mmap = 0 ,
. unlocked_ioctl = mod_ioctl ,
} ;
static struct dvb_device dvbdev_mod = {
. priv = 0 ,
. readers = 1 ,
. writers = 1 ,
. users = 2 ,
. fops = & mod_fops ,
} ;
static int locked_gate_ctrl ( struct dvb_frontend * fe , int enable )
{
struct ddb_input * input = fe - > sec_priv ;
struct ddb_port * port = input - > port ;
struct ddb_dvb * dvb = & port - > dvb [ input - > nr & 1 ] ;
int status ;
if ( enable ) {
mutex_lock ( & port - > i2c_gate_lock ) ;
status = dvb - > i2c_gate_ctrl ( fe , 1 ) ;
} else {
status = dvb - > i2c_gate_ctrl ( fe , 0 ) ;
mutex_unlock ( & port - > i2c_gate_lock ) ;
}
return status ;
}
# ifdef CONFIG_DVB_DRXK
static int demod_attach_drxk ( struct ddb_input * input )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct dvb_frontend * fe ;
fe = dvb - > fe = dvb_attach ( drxk_attach ,
i2c , 0x29 + ( input - > nr & 1 ) ,
& dvb - > fe2 ) ;
if ( ! fe ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: No DRXK found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
fe - > sec_priv = input ;
dvb - > i2c_gate_ctrl = fe - > ops . i2c_gate_ctrl ;
fe - > ops . i2c_gate_ctrl = locked_gate_ctrl ;
return 0 ;
}
# endif
2016-11-07 21:19:53 +01:00
static int demod_attach_cxd2843 ( struct ddb_input * input , int par , int osc24 )
2015-08-05 17:22:42 +02:00
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct dvb_frontend * fe ;
2016-11-07 21:19:53 +01:00
struct cxd2843_cfg cfg ;
cfg . adr = ( input - > nr & 1 ) ? 0x6d : 0x6c ;
cfg . ts_clock = par ? 0 : 1 ;
cfg . parallel = par ? 1 : 0 ;
cfg . osc = osc24 ? 24000000 : 20500000 ;
fe = dvb - > fe = dvb_attach ( cxd2843_attach , i2c , & cfg ) ;
2015-08-05 17:22:42 +02:00
if ( ! dvb - > fe ) {
2016-11-07 21:19:53 +01:00
pr_err ( " DDBridge: No cxd2837/38/43/54 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
fe - > sec_priv = input ;
dvb - > i2c_gate_ctrl = fe - > ops . i2c_gate_ctrl ;
fe - > ops . i2c_gate_ctrl = locked_gate_ctrl ;
return 0 ;
}
static int demod_attach_stv0367dd ( struct ddb_input * input )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct dvb_frontend * fe ;
struct stv0367_cfg cfg = { . cont_clock = 0 } ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
cfg . adr = 0x1f - ( input - > nr & 1 ) ;
if ( input - > port - > dev - > link [ input - > port - > lnr ] . info - > con_clock )
cfg . cont_clock = 1 ;
fe = dvb - > fe = dvb_attach ( stv0367_attach , i2c ,
& cfg ,
& dvb - > fe2 ) ;
if ( ! dvb - > fe ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: No stv0367 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
fe - > sec_priv = input ;
dvb - > i2c_gate_ctrl = fe - > ops . i2c_gate_ctrl ;
fe - > ops . i2c_gate_ctrl = locked_gate_ctrl ;
return 0 ;
}
static int tuner_attach_tda18271 ( struct ddb_input * input )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct dvb_frontend * fe ;
if ( dvb - > fe - > ops . i2c_gate_ctrl )
dvb - > fe - > ops . i2c_gate_ctrl ( dvb - > fe , 1 ) ;
fe = dvb_attach ( tda18271c2dd_attach , dvb - > fe , i2c , 0x60 ) ;
if ( dvb - > fe - > ops . i2c_gate_ctrl )
dvb - > fe - > ops . i2c_gate_ctrl ( dvb - > fe , 0 ) ;
if ( ! fe ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: No TDA18271 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
return 0 ;
}
static int tuner_attach_tda18212dd ( struct ddb_input * input )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct dvb_frontend * fe ;
fe = dvb_attach ( tda18212dd_attach , dvb - > fe , i2c ,
( input - > nr & 1 ) ? 0x63 : 0x60 ) ;
if ( ! fe ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: No TDA18212 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
return 0 ;
}
# ifdef CONFIG_DVB_TDA18212
struct tda18212_config tda18212_0 = {
. i2c_address = 0x60 ,
} ;
struct tda18212_config tda18212_1 = {
. i2c_address = 0x63 ,
} ;
static int tuner_attach_tda18212 ( struct ddb_input * input )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct dvb_frontend * fe ;
struct tda18212_config * cfg ;
cfg = ( input - > nr & 1 ) ? & tda18212_1 : & tda18212_0 ;
fe = dvb_attach ( tda18212_attach , dvb - > fe , i2c , cfg ) ;
if ( ! fe ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: No TDA18212 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
return 0 ;
}
# endif
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static struct stv090x_config stv0900 = {
. device = STV0900 ,
. demod_mode = STV090x_DUAL ,
. clk_mode = STV090x_CLK_EXT ,
. xtal = 27000000 ,
. address = 0x69 ,
. ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED ,
. ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED ,
. ts1_tei = 1 ,
. ts2_tei = 1 ,
. repeater_level = STV090x_RPTLEVEL_16 ,
. adc1_range = STV090x_ADC_1Vpp ,
. adc2_range = STV090x_ADC_1Vpp ,
. diseqc_envelope_mode = true ,
} ;
static struct stv090x_config stv0900_aa = {
. device = STV0900 ,
. demod_mode = STV090x_DUAL ,
. clk_mode = STV090x_CLK_EXT ,
. xtal = 27000000 ,
. address = 0x68 ,
. ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED ,
. ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED ,
. ts1_tei = 1 ,
. ts2_tei = 1 ,
. repeater_level = STV090x_RPTLEVEL_16 ,
. adc1_range = STV090x_ADC_1Vpp ,
. adc2_range = STV090x_ADC_1Vpp ,
. diseqc_envelope_mode = true ,
} ;
static struct stv6110x_config stv6110a = {
. addr = 0x60 ,
. refclk = 27000000 ,
. clk_div = 1 ,
} ;
static struct stv6110x_config stv6110b = {
. addr = 0x63 ,
. refclk = 27000000 ,
. clk_div = 1 ,
} ;
static int demod_attach_stv0900 ( struct ddb_input * input , int type )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct stv090x_config * feconf = type ? & stv0900_aa : & stv0900 ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
dvb - > fe = dvb_attach ( stv090x_attach , feconf , i2c ,
( input - > nr & 1 ) ? STV090x_DEMODULATOR_1
: STV090x_DEMODULATOR_0 ) ;
if ( ! dvb - > fe ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: No STV0900 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
if ( ! dvb_attach ( lnbh24_attach , dvb - > fe , i2c , 0 ,
0 , ( input - > nr & 1 ) ?
( 0x09 - type ) : ( 0x0b - type ) ) ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: No LNBH24 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
return 0 ;
}
static int tuner_attach_stv6110 ( struct ddb_input * input , int type )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct stv090x_config * feconf = type ? & stv0900_aa : & stv0900 ;
struct stv6110x_config * tunerconf = ( input - > nr & 1 ) ?
& stv6110b : & stv6110a ;
struct stv6110x_devctl * ctl ;
ctl = dvb_attach ( stv6110x_attach , dvb - > fe , tunerconf , i2c ) ;
if ( ! ctl ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: No STV6110X found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: attach tuner input %d adr %02x \n " ,
2015-08-05 17:22:42 +02:00
input - > nr , tunerconf - > addr ) ;
feconf - > tuner_init = ctl - > tuner_init ;
feconf - > tuner_sleep = ctl - > tuner_sleep ;
feconf - > tuner_set_mode = ctl - > tuner_set_mode ;
feconf - > tuner_set_frequency = ctl - > tuner_set_frequency ;
feconf - > tuner_get_frequency = ctl - > tuner_get_frequency ;
feconf - > tuner_set_bandwidth = ctl - > tuner_set_bandwidth ;
feconf - > tuner_get_bandwidth = ctl - > tuner_get_bandwidth ;
feconf - > tuner_set_bbgain = ctl - > tuner_set_bbgain ;
feconf - > tuner_get_bbgain = ctl - > tuner_get_bbgain ;
feconf - > tuner_set_refclk = ctl - > tuner_set_refclk ;
feconf - > tuner_get_status = ctl - > tuner_get_status ;
return 0 ;
}
2015-12-10 18:26:45 +01:00
static struct stv0910_cfg stv0910_p = {
2015-08-05 17:22:42 +02:00
. adr = 0x68 ,
. parallel = 1 ,
. rptlvl = 4 ,
. clk = 30000000 ,
} ;
static int demod_attach_stv0910 ( struct ddb_input * input , int type )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
2015-12-10 18:26:45 +01:00
struct stv0910_cfg cfg = stv0910_p ;
2015-08-05 17:22:42 +02:00
2016-12-30 15:03:38 +01:00
if ( stv0910_single )
cfg . single = 1 ;
2015-12-10 18:26:45 +01:00
if ( type )
cfg . parallel = 2 ;
dvb - > fe = dvb_attach ( stv0910_attach , i2c , & cfg , ( input - > nr & 1 ) ) ;
if ( ! dvb - > fe ) {
cfg . adr = 0x6c ;
2015-08-05 17:22:42 +02:00
dvb - > fe = dvb_attach ( stv0910_attach , i2c ,
2015-12-10 18:26:45 +01:00
& cfg , ( input - > nr & 1 ) ) ;
}
2015-08-05 17:22:42 +02:00
if ( ! dvb - > fe ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: No STV0910 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
if ( ! dvb_attach ( lnbh25_attach , dvb - > fe , i2c ,
2015-10-22 14:55:55 +02:00
( ( input - > nr & 1 ) ? 0x0d : 0x0c ) ) ) {
2015-08-05 17:22:42 +02:00
if ( ! dvb_attach ( lnbh25_attach , dvb - > fe , i2c ,
2015-10-22 14:55:55 +02:00
( ( input - > nr & 1 ) ? 0x09 : 0x08 ) ) ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: No LNBH25 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
}
return 0 ;
}
static int tuner_attach_stv6111 ( struct ddb_input * input , int type )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct dvb_frontend * fe ;
u8 adr = ( type ? 0 : 4 ) + ( ( input - > nr & 1 ) ? 0x63 : 0x60 ) ;
fe = dvb_attach ( stv6111_attach , dvb - > fe , i2c , adr ) ;
if ( ! fe ) {
fe = dvb_attach ( stv6111_attach , dvb - > fe , i2c , adr & ~ 4 ) ;
if ( ! fe ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: No STV6111 found at 0x%02x! \n " , adr ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
}
return 0 ;
}
static int lnb_command ( struct ddb * dev , u32 link , u32 lnb , u32 cmd )
{
u32 c , v = 0 , tag = DDB_LINK_TAG ( link ) ;
v = LNB_TONE & ( dev - > link [ link ] . lnb . tone < < ( 15 - lnb ) ) ;
2016-03-24 12:10:20 +01:00
/*pr_info("lnb_control[%u] = %08x\n", lnb, cmd | v);*/
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , cmd | v , tag | LNB_CONTROL ( lnb ) ) ;
for ( c = 0 ; c < 10 ; c + + ) {
v = ddbreadl ( dev , tag | LNB_CONTROL ( lnb ) ) ;
2016-03-24 12:10:20 +01:00
/*pr_info("ctrl = %08x\n", v);*/
2015-08-05 17:22:42 +02:00
if ( ( v & LNB_BUSY ) = = 0 )
break ;
msleep ( 20 ) ;
}
2015-08-31 20:53:22 +02:00
if ( c = = 10 )
2017-04-16 21:20:52 +02:00
pr_info ( " DDBridge: lnb_command lnb = %08x cmd = %08x \n " ,
lnb , cmd ) ;
2015-08-05 17:22:42 +02:00
return 0 ;
}
static int max_send_master_cmd ( struct dvb_frontend * fe ,
struct dvb_diseqc_master_cmd * cmd )
{
struct ddb_input * input = fe - > sec_priv ;
struct ddb_port * port = input - > port ;
struct ddb * dev = port - > dev ;
struct ddb_dvb * dvb = & port - > dvb [ input - > nr & 1 ] ;
u32 tag = DDB_LINK_TAG ( port - > lnr ) ;
int i ;
u32 fmode = dev - > link [ port - > lnr ] . lnb . fmode ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( fmode = = 2 | | fmode = = 1 )
return 0 ;
if ( dvb - > diseqc_send_master_cmd )
dvb - > diseqc_send_master_cmd ( fe , cmd ) ;
mutex_lock ( & dev - > link [ port - > lnr ] . lnb . lock ) ;
ddbwritel ( dev , 0 , tag | LNB_BUF_LEVEL ( dvb - > input ) ) ;
for ( i = 0 ; i < cmd - > msg_len ; i + + )
ddbwritel ( dev , cmd - > msg [ i ] , tag | LNB_BUF_WRITE ( dvb - > input ) ) ;
lnb_command ( dev , port - > lnr , dvb - > input , LNB_CMD_DISEQC ) ;
mutex_unlock ( & dev - > link [ port - > lnr ] . lnb . lock ) ;
return 0 ;
}
2017-04-07 22:21:06 +02:00
static int lnb_send_diseqc ( struct ddb * dev , u32 link , u32 input ,
struct dvb_diseqc_master_cmd * cmd )
{
u32 tag = DDB_LINK_TAG ( link ) ;
int i ;
ddbwritel ( dev , 0 , tag | LNB_BUF_LEVEL ( input ) ) ;
for ( i = 0 ; i < cmd - > msg_len ; i + + )
ddbwritel ( dev , cmd - > msg [ i ] , tag | LNB_BUF_WRITE ( input ) ) ;
lnb_command ( dev , link , input , LNB_CMD_DISEQC ) ;
return 0 ;
}
2017-04-16 21:20:52 +02:00
static int lnb_set_sat ( struct ddb * dev , u32 link ,
u32 input , u32 sat , u32 band , u32 hor )
2017-04-07 22:21:06 +02:00
{
struct dvb_diseqc_master_cmd cmd = {
. msg = { 0xe0 , 0x10 , 0x38 , 0xf0 , 0x00 , 0x00 } ,
. msg_len = 4
} ;
2017-04-16 21:20:52 +02:00
cmd . msg [ 3 ] = 0xf0 | ( ( ( sat < < 2 ) & 0x0c ) |
( band ? 1 : 0 ) | ( hor ? 2 : 0 ) ) ;
2017-04-07 22:21:06 +02:00
return lnb_send_diseqc ( dev , link , input , & cmd ) ;
}
2016-03-24 12:10:20 +01:00
static int lnb_set_tone ( struct ddb * dev , u32 link , u32 input ,
fe_sec_tone_mode_t tone )
2015-08-05 17:22:42 +02:00
{
int s = 0 ;
2016-03-24 12:10:20 +01:00
u32 mask = ( 1ULL < < input ) ;
2015-08-05 17:22:42 +02:00
switch ( tone ) {
case SEC_TONE_OFF :
if ( ! ( dev - > link [ link ] . lnb . tone & mask ) )
return 0 ;
dev - > link [ link ] . lnb . tone & = ~ ( 1ULL < < input ) ;
break ;
case SEC_TONE_ON :
if ( dev - > link [ link ] . lnb . tone & mask )
return 0 ;
dev - > link [ link ] . lnb . tone | = ( 1ULL < < input ) ;
break ;
default :
s = - EINVAL ;
break ;
} ;
if ( ! s )
s = lnb_command ( dev , link , input , LNB_CMD_NOP ) ;
return s ;
}
2016-03-24 12:10:20 +01:00
static int lnb_set_voltage ( struct ddb * dev , u32 link , u32 input ,
fe_sec_voltage_t voltage )
2015-08-05 17:22:42 +02:00
{
int s = 0 ;
if ( dev - > link [ link ] . lnb . oldvoltage [ input ] = = voltage )
return 0 ;
switch ( voltage ) {
case SEC_VOLTAGE_OFF :
if ( dev - > link [ link ] . lnb . voltage [ input ] )
return 0 ;
lnb_command ( dev , link , input , LNB_CMD_OFF ) ;
break ;
case SEC_VOLTAGE_13 :
lnb_command ( dev , link , input , LNB_CMD_LOW ) ;
break ;
case SEC_VOLTAGE_18 :
lnb_command ( dev , link , input , LNB_CMD_HIGH ) ;
break ;
default :
s = - EINVAL ;
break ;
} ;
dev - > link [ link ] . lnb . oldvoltage [ input ] = voltage ;
return s ;
}
static int max_set_input_unlocked ( struct dvb_frontend * fe , int in )
{
struct ddb_input * input = fe - > sec_priv ;
struct ddb_port * port = input - > port ;
struct ddb * dev = port - > dev ;
struct ddb_dvb * dvb = & port - > dvb [ input - > nr & 1 ] ;
int res = 0 ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( in > 3 )
return - EINVAL ;
if ( dvb - > input ! = in ) {
u32 bit = ( 1ULL < < input - > nr ) ;
u32 obit = dev - > link [ port - > lnr ] . lnb . voltage [ dvb - > input ] & bit ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
dev - > link [ port - > lnr ] . lnb . voltage [ dvb - > input ] & = ~ bit ;
dvb - > input = in ;
dev - > link [ port - > lnr ] . lnb . voltage [ dvb - > input ] | = obit ;
}
res = dvb - > set_input ( fe , in ) ;
return res ;
}
static int max_set_input ( struct dvb_frontend * fe , int in )
{
struct ddb_input * input = fe - > sec_priv ;
struct ddb_port * port = input - > port ;
struct ddb * dev = input - > port - > dev ;
int res ;
2016-03-24 12:10:20 +01:00
mutex_lock ( & dev - > link [ port - > lnr ] . lnb . lock ) ;
2015-08-05 17:22:42 +02:00
res = max_set_input_unlocked ( fe , in ) ;
mutex_unlock ( & dev - > link [ port - > lnr ] . lnb . lock ) ;
return res ;
}
static int max_set_tone ( struct dvb_frontend * fe , fe_sec_tone_mode_t tone )
{
struct ddb_input * input = fe - > sec_priv ;
struct ddb_port * port = input - > port ;
struct ddb * dev = port - > dev ;
struct ddb_dvb * dvb = & port - > dvb [ input - > nr & 1 ] ;
int tuner = 0 ;
int res = 0 ;
u32 fmode = dev - > link [ port - > lnr ] . lnb . fmode ;
2016-03-24 12:10:20 +01:00
mutex_lock ( & dev - > link [ port - > lnr ] . lnb . lock ) ;
2015-08-05 17:22:42 +02:00
dvb - > tone = tone ;
switch ( fmode ) {
default :
case 0 :
case 3 :
res = lnb_set_tone ( dev , port - > lnr , dvb - > input , tone ) ;
break ;
case 1 :
case 2 :
if ( old_quattro ) {
if ( dvb - > tone = = SEC_TONE_ON )
tuner | = 2 ;
if ( dvb - > voltage = = SEC_VOLTAGE_18 )
tuner | = 1 ;
} else {
if ( dvb - > tone = = SEC_TONE_ON )
tuner | = 1 ;
if ( dvb - > voltage = = SEC_VOLTAGE_18 )
tuner | = 2 ;
}
res = max_set_input_unlocked ( fe , tuner ) ;
break ;
}
mutex_unlock ( & dev - > link [ port - > lnr ] . lnb . lock ) ;
return res ;
}
static int max_set_voltage ( struct dvb_frontend * fe , fe_sec_voltage_t voltage )
{
struct ddb_input * input = fe - > sec_priv ;
struct ddb_port * port = input - > port ;
struct ddb * dev = port - > dev ;
struct ddb_dvb * dvb = & port - > dvb [ input - > nr & 1 ] ;
int tuner = 0 ;
u32 nv , ov = dev - > link [ port - > lnr ] . lnb . voltages ;
int res = 0 ;
u32 fmode = dev - > link [ port - > lnr ] . lnb . fmode ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
mutex_lock ( & dev - > link [ port - > lnr ] . lnb . lock ) ;
dvb - > voltage = voltage ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
switch ( fmode ) {
case 3 :
default :
case 0 :
if ( fmode = = 3 )
max_set_input_unlocked ( fe , 0 ) ;
2016-03-24 12:10:20 +01:00
if ( voltage = = SEC_VOLTAGE_OFF )
dev - > link [ port - > lnr ] . lnb . voltage [ dvb - > input ] & =
~ ( 1ULL < < input - > nr ) ;
else
dev - > link [ port - > lnr ] . lnb . voltage [ dvb - > input ] | =
( 1ULL < < input - > nr ) ;
2015-08-05 17:22:42 +02:00
res = lnb_set_voltage ( dev , port - > lnr , dvb - > input , voltage ) ;
break ;
case 1 :
case 2 :
2016-03-24 12:10:20 +01:00
if ( voltage = = SEC_VOLTAGE_OFF )
dev - > link [ port - > lnr ] . lnb . voltages & =
~ ( 1ULL < < input - > nr ) ;
2015-08-05 17:22:42 +02:00
else
2016-03-24 12:10:20 +01:00
dev - > link [ port - > lnr ] . lnb . voltages | =
( 1ULL < < input - > nr ) ;
2015-08-05 17:22:42 +02:00
nv = dev - > link [ port - > lnr ] . lnb . voltages ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( old_quattro ) {
if ( dvb - > tone = = SEC_TONE_ON )
tuner | = 2 ;
if ( dvb - > voltage = = SEC_VOLTAGE_18 )
tuner | = 1 ;
} else {
if ( dvb - > tone = = SEC_TONE_ON )
tuner | = 1 ;
if ( dvb - > voltage = = SEC_VOLTAGE_18 )
tuner | = 2 ;
}
res = max_set_input_unlocked ( fe , tuner ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( nv ! = ov ) {
if ( nv ) {
2016-03-24 12:10:20 +01:00
lnb_set_voltage ( dev , port - > lnr , 0 ,
SEC_VOLTAGE_13 ) ;
2015-08-05 17:22:42 +02:00
if ( fmode = = 1 ) {
2016-03-24 12:10:20 +01:00
lnb_set_voltage ( dev , port - > lnr , 0 ,
SEC_VOLTAGE_13 ) ;
2015-08-05 17:22:42 +02:00
if ( old_quattro ) {
2016-03-24 12:10:20 +01:00
lnb_set_voltage ( dev ,
port - > lnr , 1 ,
SEC_VOLTAGE_18 ) ;
lnb_set_voltage ( dev , port - > lnr ,
2 ,
SEC_VOLTAGE_13 ) ;
2015-08-05 17:22:42 +02:00
} else {
2016-03-24 12:10:20 +01:00
lnb_set_voltage ( dev , port - > lnr ,
1 ,
SEC_VOLTAGE_13 ) ;
lnb_set_voltage ( dev , port - > lnr ,
2 ,
SEC_VOLTAGE_18 ) ;
2015-08-05 17:22:42 +02:00
}
2016-03-24 12:10:20 +01:00
lnb_set_voltage ( dev , port - > lnr , 3 ,
SEC_VOLTAGE_18 ) ;
2015-08-05 17:22:42 +02:00
}
} else {
2016-03-24 12:10:20 +01:00
lnb_set_voltage ( dev , port - > lnr ,
0 , SEC_VOLTAGE_OFF ) ;
2015-08-05 17:22:42 +02:00
if ( fmode = = 1 ) {
2016-03-24 12:10:20 +01:00
lnb_set_voltage ( dev , port - > lnr , 1 ,
SEC_VOLTAGE_OFF ) ;
lnb_set_voltage ( dev , port - > lnr , 2 ,
SEC_VOLTAGE_OFF ) ;
lnb_set_voltage ( dev , port - > lnr , 3 ,
SEC_VOLTAGE_OFF ) ;
2015-08-05 17:22:42 +02:00
}
}
}
break ;
}
mutex_unlock ( & dev - > link [ port - > lnr ] . lnb . lock ) ;
return res ;
}
static int max_enable_high_lnb_voltage ( struct dvb_frontend * fe , long arg )
{
return 0 ;
}
static int max_send_burst ( struct dvb_frontend * fe , fe_sec_mini_cmd_t burst )
{
return 0 ;
}
static int mxl_fw_read ( void * priv , u8 * buf , u32 len )
{
struct ddb_link * link = priv ;
struct ddb * dev = link - > dev ;
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: Read mxl_fw from link %u \n " , link - > nr ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
return ddbridge_flashread ( dev , link - > nr , buf , 0xc0000 , len ) ;
}
2015-08-31 20:53:22 +02:00
static int lnb_init_fmode ( struct ddb * dev , struct ddb_link * link , u32 fm )
2015-08-05 17:22:42 +02:00
{
u32 l = link - > nr ;
2015-08-31 20:53:22 +02:00
if ( link - > lnb . fmode = = fm )
2015-08-05 17:22:42 +02:00
return 0 ;
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: Set fmode link %u = %u \n " , l , fm ) ;
2015-08-31 20:53:22 +02:00
mutex_lock ( & link - > lnb . lock ) ;
if ( fm = = 2 | | fm = = 1 ) {
2017-04-07 22:21:06 +02:00
if ( fmode_sat > = 0 ) {
lnb_set_sat ( dev , l , 0 , fmode_sat , 0 , 0 ) ;
if ( old_quattro ) {
lnb_set_sat ( dev , l , 1 , fmode_sat , 0 , 1 ) ;
lnb_set_sat ( dev , l , 2 , fmode_sat , 1 , 0 ) ;
} else {
lnb_set_sat ( dev , l , 1 , fmode_sat , 1 , 0 ) ;
lnb_set_sat ( dev , l , 2 , fmode_sat , 0 , 1 ) ;
}
lnb_set_sat ( dev , l , 3 , fmode_sat , 1 , 1 ) ;
}
2015-08-05 17:22:42 +02:00
lnb_set_tone ( dev , l , 0 , SEC_TONE_OFF ) ;
if ( old_quattro ) {
lnb_set_tone ( dev , l , 1 , SEC_TONE_OFF ) ;
lnb_set_tone ( dev , l , 2 , SEC_TONE_ON ) ;
} else {
lnb_set_tone ( dev , l , 1 , SEC_TONE_ON ) ;
lnb_set_tone ( dev , l , 2 , SEC_TONE_OFF ) ;
}
lnb_set_tone ( dev , l , 3 , SEC_TONE_ON ) ;
}
2015-08-31 20:53:22 +02:00
link - > lnb . fmode = fm ;
mutex_unlock ( & link - > lnb . lock ) ;
2015-08-05 17:22:42 +02:00
return 0 ;
}
static struct mxl5xx_cfg mxl5xx = {
. adr = 0x60 ,
. type = 0x01 ,
. clk = 27000000 ,
. ts_clk = 139 ,
. cap = 12 ,
. fw_read = mxl_fw_read ,
} ;
static int fe_attach_mxl5xx ( struct ddb_input * input )
{
struct ddb * dev = input - > port - > dev ;
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct ddb_port * port = input - > port ;
struct ddb_link * link = & dev - > link [ port - > lnr ] ;
struct mxl5xx_cfg cfg ;
int demod , tuner ;
cfg = mxl5xx ;
cfg . fw_priv = link ;
if ( dev - > link [ 0 ] . info - > type = = DDB_OCTONET )
2016-03-24 12:10:20 +01:00
; /*cfg.ts_clk = 69;*/
2015-08-05 17:22:42 +02:00
demod = input - > nr ;
tuner = demod & 3 ;
if ( fmode = = 3 )
tuner = 0 ;
dvb - > fe = dvb_attach ( mxl5xx_attach , i2c , & cfg , demod , tuner ) ;
if ( ! dvb - > fe ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: No MXL5XX found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
if ( input - > nr < 4 ) {
lnb_command ( dev , port - > lnr , input - > nr , LNB_CMD_INIT ) ;
lnb_set_voltage ( dev , port - > lnr , input - > nr , SEC_VOLTAGE_OFF ) ;
}
lnb_init_fmode ( dev , link , fmode ) ;
dvb - > fe - > ops . set_voltage = max_set_voltage ;
dvb - > fe - > ops . enable_high_lnb_voltage = max_enable_high_lnb_voltage ;
dvb - > fe - > ops . set_tone = max_set_tone ;
dvb - > diseqc_send_master_cmd = dvb - > fe - > ops . diseqc_send_master_cmd ;
dvb - > fe - > ops . diseqc_send_master_cmd = max_send_master_cmd ;
dvb - > fe - > ops . diseqc_send_burst = max_send_burst ;
dvb - > fe - > sec_priv = input ;
dvb - > set_input = dvb - > fe - > ops . set_input ;
dvb - > fe - > ops . set_input = max_set_input ;
dvb - > input = tuner ;
return 0 ;
}
#if 0
static int start_input ( struct ddb_input * input )
{
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
if ( ! dvb - > users )
ddb_input_start_all ( input ) ;
return + + dvb - > users ;
}
static int stop_input ( struct ddb_input * input )
{
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
if ( - - dvb - > users )
return dvb - > users ;
ddb_input_stop_all ( input ) ;
return 0 ;
}
# endif
static int start_feed ( struct dvb_demux_feed * dvbdmxfeed )
{
struct dvb_demux * dvbdmx = dvbdmxfeed - > demux ;
struct ddb_input * input = dvbdmx - > priv ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
if ( ! dvb - > users )
ddb_input_start_all ( input ) ;
return + + dvb - > users ;
}
static int stop_feed ( struct dvb_demux_feed * dvbdmxfeed )
{
struct dvb_demux * dvbdmx = dvbdmxfeed - > demux ;
struct ddb_input * input = dvbdmx - > priv ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
if ( - - dvb - > users )
return dvb - > users ;
ddb_input_stop_all ( input ) ;
return 0 ;
}
static void dvb_input_detach ( struct ddb_input * input )
{
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct dvb_demux * dvbdemux = & dvb - > demux ;
switch ( dvb - > attached ) {
case 0x31 :
if ( dvb - > fe2 )
dvb_unregister_frontend ( dvb - > fe2 ) ;
if ( dvb - > fe )
dvb_unregister_frontend ( dvb - > fe ) ;
/* fallthrough */
case 0x30 :
dvb_frontend_detach ( dvb - > fe ) ;
dvb - > fe = dvb - > fe2 = NULL ;
/* fallthrough */
case 0x21 :
if ( input - > port - > dev - > ns_num )
dvb_netstream_release ( & dvb - > dvbns ) ;
/* fallthrough */
case 0x20 :
dvb_net_release ( & dvb - > dvbnet ) ;
/* fallthrough */
2017-04-07 22:21:06 +02:00
case 0x12 :
2015-08-05 17:22:42 +02:00
dvbdemux - > dmx . remove_frontend ( & dvbdemux - > dmx ,
& dvb - > hw_frontend ) ;
dvbdemux - > dmx . remove_frontend ( & dvbdemux - > dmx ,
& dvb - > mem_frontend ) ;
2017-04-07 22:21:06 +02:00
/* fallthrough */
case 0x11 :
2015-08-05 17:22:42 +02:00
dvb_dmxdev_release ( & dvb - > dmxdev ) ;
/* fallthrough */
case 0x10 :
dvb_dmx_release ( & dvb - > demux ) ;
/* fallthrough */
case 0x01 :
break ;
}
dvb - > attached = 0x00 ;
}
static int dvb_register_adapters ( struct ddb * dev )
{
int i , ret = 0 ;
struct ddb_port * port ;
struct dvb_adapter * adap ;
if ( adapter_alloc = = 3 | | dev - > link [ 0 ] . info - > type = = DDB_MOD | |
dev - > link [ 0 ] . info - > type = = DDB_OCTONET ) {
port = & dev - > port [ 0 ] ;
adap = port - > dvb [ 0 ] . adap ;
ret = dvb_register_adapter ( adap , " DDBridge " , THIS_MODULE ,
port - > dev - > dev ,
adapter_nr ) ;
if ( ret < 0 )
return ret ;
port - > dvb [ 0 ] . adap_registered = 1 ;
for ( i = 0 ; i < dev - > port_num ; i + + ) {
port = & dev - > port [ i ] ;
port - > dvb [ 0 ] . adap = adap ;
port - > dvb [ 1 ] . adap = adap ;
}
return 0 ;
}
for ( i = 0 ; i < dev - > port_num ; i + + ) {
port = & dev - > port [ i ] ;
switch ( port - > class ) {
case DDB_PORT_TUNER :
adap = port - > dvb [ 0 ] . adap ;
ret = dvb_register_adapter ( adap , " DDBridge " ,
THIS_MODULE ,
port - > dev - > dev ,
adapter_nr ) ;
if ( ret < 0 )
return ret ;
port - > dvb [ 0 ] . adap_registered = 1 ;
if ( adapter_alloc > 0 ) {
port - > dvb [ 1 ] . adap = port - > dvb [ 0 ] . adap ;
break ;
}
adap = port - > dvb [ 1 ] . adap ;
ret = dvb_register_adapter ( adap , " DDBridge " ,
THIS_MODULE ,
port - > dev - > dev ,
adapter_nr ) ;
if ( ret < 0 )
return ret ;
port - > dvb [ 1 ] . adap_registered = 1 ;
break ;
case DDB_PORT_CI :
case DDB_PORT_LOOP :
adap = port - > dvb [ 0 ] . adap ;
ret = dvb_register_adapter ( adap , " DDBridge " ,
THIS_MODULE ,
port - > dev - > dev ,
adapter_nr ) ;
if ( ret < 0 )
return ret ;
port - > dvb [ 0 ] . adap_registered = 1 ;
break ;
default :
if ( adapter_alloc < 2 )
break ;
adap = port - > dvb [ 0 ] . adap ;
ret = dvb_register_adapter ( adap , " DDBridge " ,
THIS_MODULE ,
port - > dev - > dev ,
adapter_nr ) ;
if ( ret < 0 )
return ret ;
port - > dvb [ 0 ] . adap_registered = 1 ;
break ;
}
}
return ret ;
}
static void dvb_unregister_adapters ( struct ddb * dev )
{
int i ;
struct ddb_port * port ;
struct ddb_dvb * dvb ;
for ( i = 0 ; i < dev - > link [ 0 ] . info - > port_num ; i + + ) {
port = & dev - > port [ i ] ;
dvb = & port - > dvb [ 0 ] ;
if ( dvb - > adap_registered )
dvb_unregister_adapter ( dvb - > adap ) ;
dvb - > adap_registered = 0 ;
dvb = & port - > dvb [ 1 ] ;
if ( dvb - > adap_registered )
dvb_unregister_adapter ( dvb - > adap ) ;
dvb - > adap_registered = 0 ;
}
}
static int dvb_input_attach ( struct ddb_input * input )
{
int ret = 0 ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct ddb_port * port = input - > port ;
struct dvb_adapter * adap = dvb - > adap ;
struct dvb_demux * dvbdemux = & dvb - > demux ;
2016-12-14 19:11:57 +01:00
int par = 0 , osc24 = 0 ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
dvb - > attached = 0x01 ;
2017-04-07 22:21:06 +02:00
dvbdemux - > priv = input ;
dvbdemux - > dmx . capabilities = DMX_TS_FILTERING |
DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING ;
dvbdemux - > start_feed = start_feed ;
dvbdemux - > stop_feed = stop_feed ;
dvbdemux - > filternum = dvbdemux - > feednum = 256 ;
ret = dvb_dmx_init ( dvbdemux ) ;
2015-08-05 17:22:42 +02:00
if ( ret < 0 )
return ret ;
dvb - > attached = 0x10 ;
2017-04-07 22:21:06 +02:00
dvb - > dmxdev . filternum = 256 ;
dvb - > dmxdev . demux = & dvbdemux - > dmx ;
ret = dvb_dmxdev_init ( & dvb - > dmxdev , adap ) ;
2015-08-05 17:22:42 +02:00
if ( ret < 0 )
return ret ;
dvb - > attached = 0x11 ;
2017-04-07 22:21:06 +02:00
dvb - > mem_frontend . source = DMX_MEMORY_FE ;
dvb - > demux . dmx . add_frontend ( & dvb - > demux . dmx , & dvb - > mem_frontend ) ;
dvb - > hw_frontend . source = DMX_FRONTEND_0 ;
dvb - > demux . dmx . add_frontend ( & dvb - > demux . dmx , & dvb - > hw_frontend ) ;
ret = dvbdemux - > dmx . connect_frontend ( & dvbdemux - > dmx , & dvb - > hw_frontend ) ;
if ( ret < 0 )
return ret ;
dvb - > attached = 0x12 ;
2015-08-05 17:22:42 +02:00
ret = dvb_net_init ( adap , & dvb - > dvbnet , dvb - > dmxdev . demux ) ;
if ( ret < 0 )
return ret ;
dvb - > attached = 0x20 ;
if ( input - > port - > dev - > ns_num ) {
ret = netstream_init ( input ) ;
if ( ret < 0 )
return ret ;
dvb - > attached = 0x21 ;
}
2015-12-13 22:26:35 +01:00
dvb - > fe = dvb - > fe2 = NULL ;
2015-08-05 17:22:42 +02:00
switch ( port - > type ) {
case DDB_TUNER_MXL5XX :
if ( fe_attach_mxl5xx ( input ) < 0 )
return - ENODEV ;
break ;
case DDB_TUNER_DVBS_ST :
if ( demod_attach_stv0900 ( input , 0 ) < 0 )
return - ENODEV ;
if ( tuner_attach_stv6110 ( input , 0 ) < 0 )
return - ENODEV ;
break ;
case DDB_TUNER_DVBS_ST_AA :
if ( demod_attach_stv0900 ( input , 1 ) < 0 )
return - ENODEV ;
if ( tuner_attach_stv6110 ( input , 1 ) < 0 )
return - ENODEV ;
break ;
case DDB_TUNER_DVBS_STV0910 :
if ( demod_attach_stv0910 ( input , 0 ) < 0 )
return - ENODEV ;
if ( tuner_attach_stv6111 ( input , 0 ) < 0 )
return - ENODEV ;
break ;
2015-12-10 18:26:45 +01:00
case DDB_TUNER_DVBS_STV0910_PR :
2015-08-05 17:22:42 +02:00
if ( demod_attach_stv0910 ( input , 1 ) < 0 )
return - ENODEV ;
if ( tuner_attach_stv6111 ( input , 1 ) < 0 )
return - ENODEV ;
break ;
2015-12-10 18:26:45 +01:00
case DDB_TUNER_DVBS_STV0910_P :
if ( demod_attach_stv0910 ( input , 0 ) < 0 )
return - ENODEV ;
if ( tuner_attach_stv6111 ( input , 1 ) < 0 )
return - ENODEV ;
break ;
2015-08-05 17:22:42 +02:00
# ifdef CONFIG_DVB_DRXK
case DDB_TUNER_DVBCT_TR :
if ( demod_attach_drxk ( input ) < 0 )
return - ENODEV ;
if ( tuner_attach_tda18271 ( input ) < 0 )
return - ENODEV ;
break ;
# endif
case DDB_TUNER_DVBCT_ST :
if ( demod_attach_stv0367dd ( input ) < 0 )
return - ENODEV ;
if ( tuner_attach_tda18212dd ( input ) < 0 )
return - ENODEV ;
break ;
2016-12-14 19:11:57 +01:00
case DDB_TUNER_DVBC2T2I_SONY_P :
if ( input - > port - > dev - > link [ input - > port - > lnr ] . info - > ts_quirks &
TS_QUIRK_ALT_OSC )
osc24 = 0 ;
else
osc24 = 1 ;
2015-08-05 17:22:42 +02:00
case DDB_TUNER_DVBCT2_SONY_P :
case DDB_TUNER_DVBC2T2_SONY_P :
case DDB_TUNER_ISDBT_SONY_P :
2016-03-24 12:10:20 +01:00
if ( input - > port - > dev - > link [ input - > port - > lnr ] . info - > ts_quirks &
TS_QUIRK_SERIAL )
2015-12-10 18:26:45 +01:00
par = 0 ;
else
2015-09-17 18:54:25 +02:00
par = 1 ;
2016-12-14 19:11:57 +01:00
if ( demod_attach_cxd2843 ( input , par , osc24 ) < 0 )
2016-11-07 21:19:53 +01:00
return - ENODEV ;
if ( tuner_attach_tda18212dd ( input ) < 0 )
return - ENODEV ;
break ;
case DDB_TUNER_DVBC2T2I_SONY :
2016-12-14 19:11:57 +01:00
osc24 = 1 ;
case DDB_TUNER_DVBCT2_SONY :
case DDB_TUNER_DVBC2T2_SONY :
case DDB_TUNER_ISDBT_SONY :
if ( demod_attach_cxd2843 ( input , 0 , osc24 ) < 0 )
2015-08-05 17:22:42 +02:00
return - ENODEV ;
if ( tuner_attach_tda18212dd ( input ) < 0 )
return - ENODEV ;
break ;
default :
return 0 ;
}
dvb - > attached = 0x30 ;
2017-04-07 22:21:06 +02:00
2015-08-05 17:22:42 +02:00
if ( dvb - > fe ) {
if ( dvb_register_frontend ( adap , dvb - > fe ) < 0 )
return - ENODEV ;
}
if ( dvb - > fe2 ) {
if ( dvb_register_frontend ( adap , dvb - > fe2 ) < 0 )
return - ENODEV ;
dvb - > fe2 - > tuner_priv = dvb - > fe - > tuner_priv ;
memcpy ( & dvb - > fe2 - > ops . tuner_ops ,
& dvb - > fe - > ops . tuner_ops ,
sizeof ( struct dvb_tuner_ops ) ) ;
}
dvb - > attached = 0x31 ;
return 0 ;
}
static int port_has_encti ( struct ddb_port * port )
{
u8 val ;
int ret = i2c_read_reg ( & port - > i2c - > adap , 0x20 , 0 , & val ) ;
if ( ! ret )
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: [0x20]=0x%02x \n " , val ) ;
2015-08-05 17:22:42 +02:00
return ret ? 0 : 1 ;
}
static int port_has_cxd ( struct ddb_port * port , u8 * type )
{
u8 val ;
u8 probe [ 4 ] = { 0xe0 , 0x00 , 0x00 , 0x00 } , data [ 4 ] ;
struct i2c_msg msgs [ 2 ] = { { . addr = 0x40 , . flags = 0 ,
. buf = probe , . len = 4 } ,
{ . addr = 0x40 , . flags = I2C_M_RD ,
. buf = data , . len = 4 } } ;
val = i2c_transfer ( & port - > i2c - > adap , msgs , 2 ) ;
if ( val ! = 2 )
return 0 ;
if ( data [ 0 ] = = 0x02 & & data [ 1 ] = = 0x2b & & data [ 3 ] = = 0x43 )
* type = 2 ;
else
* type = 1 ;
return 1 ;
}
static int port_has_xo2 ( struct ddb_port * port , u8 * type , u8 * id )
{
u8 probe [ 1 ] = { 0x00 } , data [ 4 ] ;
if ( i2c_io ( & port - > i2c - > adap , 0x10 , probe , 1 , data , 4 ) )
return 0 ;
if ( data [ 0 ] = = ' D ' & & data [ 1 ] = = ' F ' ) {
* id = data [ 2 ] ;
* type = 1 ;
return 1 ;
}
if ( data [ 0 ] = = ' C ' & & data [ 1 ] = = ' I ' ) {
* id = data [ 2 ] ;
* type = 2 ;
return 1 ;
}
return 0 ;
}
static int port_has_stv0900 ( struct ddb_port * port )
{
u8 val ;
if ( i2c_read_reg16 ( & port - > i2c - > adap , 0x69 , 0xf100 , & val ) < 0 )
return 0 ;
return 1 ;
}
static int port_has_stv0900_aa ( struct ddb_port * port , u8 * id )
{
if ( i2c_read_reg16 ( & port - > i2c - > adap , 0x68 , 0xf100 , id ) < 0 )
return 0 ;
return 1 ;
}
static int port_has_drxks ( struct ddb_port * port )
{
u8 val ;
if ( i2c_read ( & port - > i2c - > adap , 0x29 , & val ) < 0 )
return 0 ;
if ( i2c_read ( & port - > i2c - > adap , 0x2a , & val ) < 0 )
return 0 ;
return 1 ;
}
static int port_has_stv0367 ( struct ddb_port * port )
{
u8 val ;
if ( i2c_read_reg16 ( & port - > i2c - > adap , 0x1e , 0xf000 , & val ) < 0 )
return 0 ;
if ( val ! = 0x60 )
return 0 ;
if ( i2c_read_reg16 ( & port - > i2c - > adap , 0x1f , 0xf000 , & val ) < 0 )
return 0 ;
if ( val ! = 0x60 )
return 0 ;
return 1 ;
}
static int init_xo2 ( struct ddb_port * port )
{
struct i2c_adapter * i2c = & port - > i2c - > adap ;
struct ddb * dev = port - > dev ;
u8 val , data [ 2 ] ;
int res ;
res = i2c_read_regs ( i2c , 0x10 , 0x04 , data , 2 ) ;
if ( res < 0 )
return res ;
if ( data [ 0 ] ! = 0x01 ) {
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: Port %d: invalid XO2 \n " , port - > nr ) ;
2015-08-05 17:22:42 +02:00
return - 1 ;
}
i2c_read_reg ( i2c , 0x10 , 0x08 , & val ) ;
if ( val ! = 0 ) {
i2c_write_reg ( i2c , 0x10 , 0x08 , 0x00 ) ;
msleep ( 100 ) ;
}
/* Enable tuner power, disable pll, reset demods */
i2c_write_reg ( i2c , 0x10 , 0x08 , 0x04 ) ;
usleep_range ( 2000 , 3000 ) ;
/* Release demod resets */
i2c_write_reg ( i2c , 0x10 , 0x08 , 0x07 ) ;
/* speed: 0=55,1=75,2=90,3=104 MBit/s */
2016-04-12 12:18:09 +02:00
i2c_write_reg ( i2c , 0x10 , 0x09 , xo2_speed ) ;
2015-08-05 17:22:42 +02:00
if ( dev - > link [ port - > lnr ] . info - > con_clock ) {
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: Setting continuous clock for XO2 \n " ) ;
2015-08-05 17:22:42 +02:00
i2c_write_reg ( i2c , 0x10 , 0x0a , 0x03 ) ;
i2c_write_reg ( i2c , 0x10 , 0x0b , 0x03 ) ;
} else {
i2c_write_reg ( i2c , 0x10 , 0x0a , 0x01 ) ;
i2c_write_reg ( i2c , 0x10 , 0x0b , 0x01 ) ;
}
usleep_range ( 2000 , 3000 ) ;
2016-03-24 12:10:20 +01:00
/* Start XO2 PLL */
2015-08-05 17:22:42 +02:00
i2c_write_reg ( i2c , 0x10 , 0x08 , 0x87 ) ;
return 0 ;
}
static int init_xo2_ci ( struct ddb_port * port )
{
struct i2c_adapter * i2c = & port - > i2c - > adap ;
struct ddb * dev = port - > dev ;
u8 val , data [ 2 ] ;
int res ;
res = i2c_read_regs ( i2c , 0x10 , 0x04 , data , 2 ) ;
if ( res < 0 )
return res ;
if ( data [ 0 ] > 1 ) {
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: Port %d: invalid XO2 CI %02x \n " ,
2015-08-05 17:22:42 +02:00
port - > nr , data [ 0 ] ) ;
return - 1 ;
}
2017-04-16 21:20:52 +02:00
pr_info ( " DDBridge: Port %d: DuoFlex CI %u.%u \n " ,
port - > nr , data [ 0 ] , data [ 1 ] ) ;
2015-08-05 17:22:42 +02:00
i2c_read_reg ( i2c , 0x10 , 0x08 , & val ) ;
if ( val ! = 0 ) {
i2c_write_reg ( i2c , 0x10 , 0x08 , 0x00 ) ;
msleep ( 100 ) ;
}
/* Enable both CI */
i2c_write_reg ( i2c , 0x10 , 0x08 , 3 ) ;
usleep_range ( 2000 , 3000 ) ;
/* speed: 0=55,1=75,2=90,3=104 MBit/s */
i2c_write_reg ( i2c , 0x10 , 0x09 , 1 ) ;
i2c_write_reg ( i2c , 0x10 , 0x08 , 0x83 ) ;
usleep_range ( 2000 , 3000 ) ;
if ( dev - > link [ port - > lnr ] . info - > con_clock ) {
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: Setting continuous clock for DuoFLex CI \n " ) ;
2015-08-05 17:22:42 +02:00
i2c_write_reg ( i2c , 0x10 , 0x0a , 0x03 ) ;
i2c_write_reg ( i2c , 0x10 , 0x0b , 0x03 ) ;
} else {
i2c_write_reg ( i2c , 0x10 , 0x0a , 0x01 ) ;
i2c_write_reg ( i2c , 0x10 , 0x0b , 0x01 ) ;
}
return 0 ;
}
static int port_has_cxd28xx ( struct ddb_port * port , u8 * id )
{
struct i2c_adapter * i2c = & port - > i2c - > adap ;
int status ;
status = i2c_write_reg ( & port - > i2c - > adap , 0x6e , 0 , 0 ) ;
if ( status )
return 0 ;
status = i2c_read_reg ( i2c , 0x6e , 0xfd , id ) ;
if ( status )
return 0 ;
return 1 ;
}
static char * xo2names [ ] = {
" DUAL DVB-S2 " , " DUAL DVB-C/T/T2 " ,
" DUAL DVB-ISDBT " , " DUAL DVB-C/C2/T/T2 " ,
2016-11-07 21:19:53 +01:00
" DUAL ATSC " , " DUAL DVB-C/C2/T/T2,ISDB-T " ,
2015-08-05 17:22:42 +02:00
" " , " "
} ;
2015-10-22 14:51:36 +02:00
static char * xo2types [ ] = {
" DVBS_ST " , " DVBCT2_SONY " ,
" ISDBT_SONY " , " DVBC2T2_SONY " ,
2016-11-07 21:19:53 +01:00
" ATSC_ST " , " DVBC2T2I_SONY "
2015-10-22 14:51:36 +02:00
} ;
2015-08-05 17:22:42 +02:00
static void ddb_port_probe ( struct ddb_port * port )
{
struct ddb * dev = port - > dev ;
u32 l = port - > lnr ;
u8 id , type ;
port - > name = " NO MODULE " ;
2015-10-22 14:51:36 +02:00
port - > type_name = " NONE " ;
2015-08-05 17:22:42 +02:00
port - > class = DDB_PORT_NONE ;
2015-10-22 14:51:36 +02:00
2015-08-05 17:22:42 +02:00
/* Handle missing ports and ports without I2C */
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( port - > nr = = ts_loop ) {
port - > name = " TS LOOP " ;
port - > class = DDB_PORT_LOOP ;
return ;
}
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( port - > nr = = 1 & & dev - > link [ l ] . info - > type = = DDB_OCTOPUS_CI & &
dev - > link [ l ] . info - > i2c_mask = = 1 ) {
port - > name = " NO TAB " ;
port - > class = DDB_PORT_NONE ;
return ;
}
if ( dev - > link [ l ] . info - > type = = DDB_MOD ) {
port - > name = " MOD " ;
port - > class = DDB_PORT_MOD ;
return ;
}
2017-04-16 21:20:52 +02:00
2016-04-15 18:08:51 +02:00
if ( dev - > link [ l ] . info - > type = = DDB_OCTOPRO_HDIN ) {
2017-04-16 21:20:52 +02:00
if ( port - > nr = = 0 ) {
2016-04-15 18:08:51 +02:00
dev - > link [ l ] . info - > type = DDB_OCTOPUS ;
port - > name = " HDIN " ;
port - > class = DDB_PORT_LOOP ;
}
return ;
2017-04-16 21:20:52 +02:00
}
2015-08-05 17:22:42 +02:00
if ( dev - > link [ l ] . info - > type = = DDB_OCTOPUS_MAX ) {
port - > name = " DUAL DVB-S2 MAX " ;
2015-10-22 14:51:36 +02:00
port - > type_name = " MXL5XX " ;
2015-08-05 17:22:42 +02:00
port - > class = DDB_PORT_TUNER ;
port - > type = DDB_TUNER_MXL5XX ;
if ( port - > i2c )
ddbwritel ( dev , I2C_SPEED_400 ,
port - > i2c - > regs + I2C_TIMING ) ;
return ;
}
if ( port - > nr > 1 & & dev - > link [ l ] . info - > type = = DDB_OCTOPUS_CI ) {
port - > name = " CI internal " ;
2015-10-22 14:51:36 +02:00
port - > type_name = " INTERNAL " ;
2015-08-05 17:22:42 +02:00
port - > class = DDB_PORT_CI ;
port - > type = DDB_CI_INTERNAL ;
}
if ( ! port - > i2c )
return ;
/* Probe ports with I2C */
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( port_has_cxd ( port , & id ) ) {
if ( id = = 1 ) {
port - > name = " CI " ;
2015-10-22 14:51:36 +02:00
port - > type_name = " CXD2099 " ;
2015-08-05 17:22:42 +02:00
port - > class = DDB_PORT_CI ;
port - > type = DDB_CI_EXTERNAL_SONY ;
ddbwritel ( dev , I2C_SPEED_400 ,
port - > i2c - > regs + I2C_TIMING ) ;
} else {
2017-04-16 21:20:52 +02:00
pr_info ( " DDBridge: Port %d: Uninitialized DuoFlex \n " ,
2015-08-05 17:22:42 +02:00
port - > nr ) ;
return ;
}
} else if ( port_has_xo2 ( port , & type , & id ) ) {
ddbwritel ( dev , I2C_SPEED_400 , port - > i2c - > regs + I2C_TIMING ) ;
2016-11-07 21:19:53 +01:00
pr_info ( " DDBridge: XO2 ID %02x \n " , id ) ;
2015-08-05 17:22:42 +02:00
if ( type = = 2 ) {
port - > name = " DuoFlex CI " ;
port - > class = DDB_PORT_CI ;
port - > type = DDB_CI_EXTERNAL_XO2 ;
2015-10-22 14:51:36 +02:00
port - > type_name = " CI_XO2 " ;
2015-08-05 17:22:42 +02:00
init_xo2_ci ( port ) ;
return ;
}
id > > = 2 ;
if ( id > 5 ) {
port - > name = " unknown XO2 DuoFlex " ;
2015-10-22 14:51:36 +02:00
port - > type_name = " UNKNOWN " ;
2015-08-05 17:22:42 +02:00
} else {
port - > name = xo2names [ id ] ;
port - > class = DDB_PORT_TUNER ;
port - > type = DDB_TUNER_XO2 + id ;
2015-10-22 14:51:36 +02:00
port - > type_name = xo2types [ id ] ;
2015-08-05 17:22:42 +02:00
init_xo2 ( port ) ;
}
} else if ( port_has_cxd28xx ( port , & id ) ) {
switch ( id ) {
case 0xa4 :
2015-10-22 14:51:36 +02:00
port - > name = " DUAL DVB-C2T2 CXD2843 " ;
2015-08-05 17:22:42 +02:00
port - > type = DDB_TUNER_DVBC2T2_SONY_P ;
2015-10-22 14:51:36 +02:00
port - > type_name = " DVBC2T2_SONY " ;
2015-08-05 17:22:42 +02:00
break ;
case 0xb1 :
port - > name = " DUAL DVB-CT2 CXD2837 " ;
port - > type = DDB_TUNER_DVBCT2_SONY_P ;
2015-10-22 14:51:36 +02:00
port - > type_name = " DVBCT2_SONY " ;
2015-08-05 17:22:42 +02:00
break ;
case 0xb0 :
port - > name = " DUAL ISDB-T CXD2838 " ;
port - > type = DDB_TUNER_ISDBT_SONY_P ;
2015-10-22 14:51:36 +02:00
port - > type_name = " ISDBT_SONY " ;
2015-08-05 17:22:42 +02:00
break ;
2016-08-29 18:44:53 +02:00
case 0xc1 :
port - > name = " DUAL DVB-C2T2 ISDB-T CXD2854 " ;
2017-04-09 13:20:22 +02:00
port - > type = DDB_TUNER_DVBC2T2I_SONY_P ;
port - > type_name = " DVBC2T2I_ISDBT_SONY " ;
2016-08-29 18:44:53 +02:00
break ;
2015-08-05 17:22:42 +02:00
default :
return ;
}
port - > class = DDB_PORT_TUNER ;
ddbwritel ( dev , I2C_SPEED_400 , port - > i2c - > regs + I2C_TIMING ) ;
} else if ( port_has_stv0900 ( port ) ) {
port - > name = " DUAL DVB-S2 " ;
port - > class = DDB_PORT_TUNER ;
port - > type = DDB_TUNER_DVBS_ST ;
2015-10-22 14:51:36 +02:00
port - > type_name = " DVBS_ST " ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , I2C_SPEED_100 , port - > i2c - > regs + I2C_TIMING ) ;
} else if ( port_has_stv0900_aa ( port , & id ) ) {
port - > name = " DUAL DVB-S2 " ;
port - > class = DDB_PORT_TUNER ;
2015-12-10 18:26:45 +01:00
if ( id = = 0x51 ) {
if ( port - > nr = = 0 & &
dev - > link [ l ] . info - > ts_quirks & TS_QUIRK_REVERSED )
port - > type = DDB_TUNER_DVBS_STV0910_PR ;
else
port - > type = DDB_TUNER_DVBS_STV0910_P ;
port - > type_name = " DVBS_ST_0910 " ;
} else {
2015-08-05 17:22:42 +02:00
port - > type = DDB_TUNER_DVBS_ST_AA ;
2015-12-10 18:26:45 +01:00
port - > type_name = " DVBS_ST_AA " ;
}
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , I2C_SPEED_100 , port - > i2c - > regs + I2C_TIMING ) ;
} else if ( port_has_drxks ( port ) ) {
port - > name = " DUAL DVB-C/T " ;
port - > class = DDB_PORT_TUNER ;
port - > type = DDB_TUNER_DVBCT_TR ;
2015-10-22 14:51:36 +02:00
port - > type_name = " DVBCT_TR " ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , I2C_SPEED_400 , port - > i2c - > regs + I2C_TIMING ) ;
} else if ( port_has_stv0367 ( port ) ) {
port - > name = " DUAL DVB-C/T " ;
port - > class = DDB_PORT_TUNER ;
port - > type = DDB_TUNER_DVBCT_ST ;
2015-10-22 14:51:36 +02:00
port - > type_name = " DVBCT_ST " ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , I2C_SPEED_100 , port - > i2c - > regs + I2C_TIMING ) ;
} else if ( port_has_encti ( port ) ) {
port - > name = " ENCTI " ;
port - > class = DDB_PORT_LOOP ;
2016-03-24 12:10:20 +01:00
}
2015-08-05 17:22:42 +02:00
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static int wait_ci_ready ( struct ddb_ci * ci )
{
u32 count = 10 ;
ndelay ( 500 ) ;
do {
if ( ddbreadl ( ci - > port - > dev ,
CI_CONTROL ( ci - > nr ) ) & CI_READY )
break ;
usleep_range ( 1 , 2 ) ;
if ( ( - - count ) = = 0 )
return - 1 ;
} while ( 1 ) ;
return 0 ;
}
static int read_attribute_mem ( struct dvb_ca_en50221 * ca ,
int slot , int address )
{
struct ddb_ci * ci = ca - > data ;
u32 val , off = ( address > > 1 ) & ( CI_BUFFER_SIZE - 1 ) ;
if ( address > CI_BUFFER_SIZE )
return - 1 ;
ddbwritel ( ci - > port - > dev , CI_READ_CMD | ( 1 < < 16 ) | address ,
CI_DO_READ_ATTRIBUTES ( ci - > nr ) ) ;
wait_ci_ready ( ci ) ;
val = 0xff & ddbreadl ( ci - > port - > dev , CI_BUFFER ( ci - > nr ) + off ) ;
return val ;
}
static int write_attribute_mem ( struct dvb_ca_en50221 * ca , int slot ,
int address , u8 value )
{
struct ddb_ci * ci = ca - > data ;
ddbwritel ( ci - > port - > dev , CI_WRITE_CMD | ( value < < 16 ) | address ,
CI_DO_ATTRIBUTE_RW ( ci - > nr ) ) ;
wait_ci_ready ( ci ) ;
return 0 ;
}
static int read_cam_control ( struct dvb_ca_en50221 * ca ,
int slot , u8 address )
{
u32 count = 100 ;
struct ddb_ci * ci = ca - > data ;
u32 res ;
ddbwritel ( ci - > port - > dev , CI_READ_CMD | address ,
CI_DO_IO_RW ( ci - > nr ) ) ;
ndelay ( 500 ) ;
do {
res = ddbreadl ( ci - > port - > dev , CI_READDATA ( ci - > nr ) ) ;
if ( res & CI_READY )
break ;
usleep_range ( 1 , 2 ) ;
if ( ( - - count ) = = 0 )
return - 1 ;
} while ( 1 ) ;
return 0xff & res ;
}
static int write_cam_control ( struct dvb_ca_en50221 * ca , int slot ,
u8 address , u8 value )
{
struct ddb_ci * ci = ca - > data ;
ddbwritel ( ci - > port - > dev , CI_WRITE_CMD | ( value < < 16 ) | address ,
CI_DO_IO_RW ( ci - > nr ) ) ;
wait_ci_ready ( ci ) ;
return 0 ;
}
static int slot_reset ( struct dvb_ca_en50221 * ca , int slot )
{
struct ddb_ci * ci = ca - > data ;
ddbwritel ( ci - > port - > dev , CI_POWER_ON ,
CI_CONTROL ( ci - > nr ) ) ;
msleep ( 100 ) ;
ddbwritel ( ci - > port - > dev , CI_POWER_ON | CI_RESET_CAM ,
CI_CONTROL ( ci - > nr ) ) ;
ddbwritel ( ci - > port - > dev , CI_ENABLE | CI_POWER_ON | CI_RESET_CAM ,
CI_CONTROL ( ci - > nr ) ) ;
udelay ( 20 ) ;
ddbwritel ( ci - > port - > dev , CI_ENABLE | CI_POWER_ON ,
CI_CONTROL ( ci - > nr ) ) ;
return 0 ;
}
static int slot_shutdown ( struct dvb_ca_en50221 * ca , int slot )
{
struct ddb_ci * ci = ca - > data ;
ddbwritel ( ci - > port - > dev , 0 , CI_CONTROL ( ci - > nr ) ) ;
msleep ( 300 ) ;
return 0 ;
}
static int slot_ts_enable ( struct dvb_ca_en50221 * ca , int slot )
{
struct ddb_ci * ci = ca - > data ;
u32 val = ddbreadl ( ci - > port - > dev , CI_CONTROL ( ci - > nr ) ) ;
ddbwritel ( ci - > port - > dev , val | CI_BYPASS_DISABLE ,
CI_CONTROL ( ci - > nr ) ) ;
return 0 ;
}
static int poll_slot_status ( struct dvb_ca_en50221 * ca , int slot , int open )
{
struct ddb_ci * ci = ca - > data ;
u32 val = ddbreadl ( ci - > port - > dev , CI_CONTROL ( ci - > nr ) ) ;
int stat = 0 ;
if ( val & CI_CAM_DETECT )
stat | = DVB_CA_EN50221_POLL_CAM_PRESENT ;
if ( val & CI_CAM_READY )
stat | = DVB_CA_EN50221_POLL_CAM_READY ;
return stat ;
}
static struct dvb_ca_en50221 en_templ = {
. read_attribute_mem = read_attribute_mem ,
. write_attribute_mem = write_attribute_mem ,
. read_cam_control = read_cam_control ,
. write_cam_control = write_cam_control ,
. slot_reset = slot_reset ,
. slot_shutdown = slot_shutdown ,
. slot_ts_enable = slot_ts_enable ,
. poll_slot_status = poll_slot_status ,
} ;
static void ci_attach ( struct ddb_port * port )
{
struct ddb_ci * ci = 0 ;
ci = kzalloc ( sizeof ( * ci ) , GFP_KERNEL ) ;
if ( ! ci )
return ;
memcpy ( & ci - > en , & en_templ , sizeof ( en_templ ) ) ;
ci - > en . data = ci ;
port - > en = & ci - > en ;
ci - > port = port ;
ci - > nr = port - > nr - 2 ;
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static int write_creg ( struct ddb_ci * ci , u8 data , u8 mask )
{
struct i2c_adapter * i2c = & ci - > port - > i2c - > adap ;
u8 adr = ( ci - > port - > type = = DDB_CI_EXTERNAL_XO2 ) ? 0x12 : 0x13 ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
ci - > port - > creg = ( ci - > port - > creg & ~ mask ) | data ;
return i2c_write_reg ( i2c , adr , 0x02 , ci - > port - > creg ) ;
}
static int read_attribute_mem_xo2 ( struct dvb_ca_en50221 * ca ,
int slot , int address )
{
struct ddb_ci * ci = ca - > data ;
struct i2c_adapter * i2c = & ci - > port - > i2c - > adap ;
u8 adr = ( ci - > port - > type = = DDB_CI_EXTERNAL_XO2 ) ? 0x12 : 0x13 ;
int res ;
u8 val ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
res = i2c_read_reg16 ( i2c , adr , 0x8000 | address , & val ) ;
return res ? res : val ;
}
static int write_attribute_mem_xo2 ( struct dvb_ca_en50221 * ca , int slot ,
int address , u8 value )
{
struct ddb_ci * ci = ca - > data ;
struct i2c_adapter * i2c = & ci - > port - > i2c - > adap ;
u8 adr = ( ci - > port - > type = = DDB_CI_EXTERNAL_XO2 ) ? 0x12 : 0x13 ;
return i2c_write_reg16 ( i2c , adr , 0x8000 | address , value ) ;
}
static int read_cam_control_xo2 ( struct dvb_ca_en50221 * ca ,
int slot , u8 address )
{
struct ddb_ci * ci = ca - > data ;
struct i2c_adapter * i2c = & ci - > port - > i2c - > adap ;
u8 adr = ( ci - > port - > type = = DDB_CI_EXTERNAL_XO2 ) ? 0x12 : 0x13 ;
u8 val ;
int res ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
res = i2c_read_reg ( i2c , adr , 0x20 | ( address & 3 ) , & val ) ;
return res ? res : val ;
}
static int write_cam_control_xo2 ( struct dvb_ca_en50221 * ca , int slot ,
u8 address , u8 value )
{
struct ddb_ci * ci = ca - > data ;
struct i2c_adapter * i2c = & ci - > port - > i2c - > adap ;
u8 adr = ( ci - > port - > type = = DDB_CI_EXTERNAL_XO2 ) ? 0x12 : 0x13 ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
return i2c_write_reg ( i2c , adr , 0x20 | ( address & 3 ) , value ) ;
}
static int slot_reset_xo2 ( struct dvb_ca_en50221 * ca , int slot )
{
struct ddb_ci * ci = ca - > data ;
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: %s \n " , __func__ ) ;
2015-08-05 17:22:42 +02:00
write_creg ( ci , 0x01 , 0x01 ) ;
write_creg ( ci , 0x04 , 0x04 ) ;
msleep ( 20 ) ;
write_creg ( ci , 0x02 , 0x02 ) ;
write_creg ( ci , 0x00 , 0x04 ) ;
write_creg ( ci , 0x18 , 0x18 ) ;
return 0 ;
}
static int slot_shutdown_xo2 ( struct dvb_ca_en50221 * ca , int slot )
{
struct ddb_ci * ci = ca - > data ;
2016-03-24 12:10:20 +01:00
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: %s \n " , __func__ ) ;
2016-03-24 12:10:20 +01:00
/*i2c_write_reg(i2c, adr, 0x03, 0x60);*/
/*i2c_write_reg(i2c, adr, 0x00, 0xc0);*/
2015-08-05 17:22:42 +02:00
write_creg ( ci , 0x10 , 0xff ) ;
write_creg ( ci , 0x08 , 0x08 ) ;
return 0 ;
}
static int slot_ts_enable_xo2 ( struct dvb_ca_en50221 * ca , int slot )
{
struct ddb_ci * ci = ca - > data ;
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: %s \n " , __func__ ) ;
2015-08-05 17:22:42 +02:00
write_creg ( ci , 0x00 , 0x10 ) ;
return 0 ;
}
static int poll_slot_status_xo2 ( struct dvb_ca_en50221 * ca , int slot , int open )
{
struct ddb_ci * ci = ca - > data ;
struct i2c_adapter * i2c = & ci - > port - > i2c - > adap ;
u8 adr = ( ci - > port - > type = = DDB_CI_EXTERNAL_XO2 ) ? 0x12 : 0x13 ;
u8 val = 0 ;
int stat = 0 ;
i2c_read_reg ( i2c , adr , 0x01 , & val ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( val & 2 )
stat | = DVB_CA_EN50221_POLL_CAM_PRESENT ;
if ( val & 1 )
stat | = DVB_CA_EN50221_POLL_CAM_READY ;
return stat ;
}
static struct dvb_ca_en50221 en_xo2_templ = {
. read_attribute_mem = read_attribute_mem_xo2 ,
. write_attribute_mem = write_attribute_mem_xo2 ,
. read_cam_control = read_cam_control_xo2 ,
. write_cam_control = write_cam_control_xo2 ,
. slot_reset = slot_reset_xo2 ,
. slot_shutdown = slot_shutdown_xo2 ,
. slot_ts_enable = slot_ts_enable_xo2 ,
. poll_slot_status = poll_slot_status_xo2 ,
} ;
static void ci_xo2_attach ( struct ddb_port * port )
{
struct ddb_ci * ci = 0 ;
struct i2c_adapter * i2c ;
ci = kzalloc ( sizeof ( * ci ) , GFP_KERNEL ) ;
if ( ! ci )
return ;
memcpy ( & ci - > en , & en_xo2_templ , sizeof ( en_xo2_templ ) ) ;
ci - > en . data = ci ;
port - > en = & ci - > en ;
ci - > port = port ;
ci - > nr = port - > nr - 2 ;
ci - > port - > creg = 0 ;
i2c = & ci - > port - > i2c - > adap ;
write_creg ( ci , 0x10 , 0xff ) ;
write_creg ( ci , 0x08 , 0x08 ) ;
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
struct cxd2099_cfg cxd_cfg = {
. bitrate = 72000 ,
. adr = 0x40 ,
. polarity = 1 ,
. clock_mode = 1 ,
. max_i2c = 512 ,
} ;
static int ddb_ci_attach ( struct ddb_port * port )
{
switch ( port - > type ) {
case DDB_CI_EXTERNAL_SONY :
cxd_cfg . bitrate = ci_bitrate ;
port - > en = cxd2099_attach ( & cxd_cfg , port , & port - > i2c - > adap ) ;
if ( ! port - > en )
return - ENODEV ;
dvb_ca_en50221_init ( port - > dvb [ 0 ] . adap ,
port - > en , 0 , 1 ) ;
break ;
case DDB_CI_EXTERNAL_XO2 :
case DDB_CI_EXTERNAL_XO2_B :
ci_xo2_attach ( port ) ;
if ( ! port - > en )
return - ENODEV ;
dvb_ca_en50221_init ( port - > dvb [ 0 ] . adap , port - > en , 0 , 1 ) ;
break ;
case DDB_CI_INTERNAL :
ci_attach ( port ) ;
if ( ! port - > en )
return - ENODEV ;
dvb_ca_en50221_init ( port - > dvb [ 0 ] . adap , port - > en , 0 , 1 ) ;
break ;
}
return 0 ;
}
static int ddb_port_attach ( struct ddb_port * port )
{
int ret = 0 ;
switch ( port - > class ) {
case DDB_PORT_TUNER :
ret = dvb_input_attach ( port - > input [ 0 ] ) ;
if ( ret < 0 )
break ;
ret = dvb_input_attach ( port - > input [ 1 ] ) ;
if ( ret < 0 )
break ;
port - > input [ 0 ] - > redi = port - > input [ 0 ] ;
port - > input [ 1 ] - > redi = port - > input [ 1 ] ;
break ;
case DDB_PORT_CI :
ret = ddb_ci_attach ( port ) ;
if ( ret < 0 )
break ;
case DDB_PORT_LOOP :
ret = dvb_register_device ( port - > dvb [ 0 ] . adap ,
& port - > dvb [ 0 ] . dev ,
& dvbdev_ci , ( void * ) port - > output ,
DVB_DEVICE_CI ) ;
break ;
case DDB_PORT_MOD :
ret = dvb_register_device ( port - > dvb [ 0 ] . adap ,
& port - > dvb [ 0 ] . dev ,
& dvbdev_mod , ( void * ) port - > output ,
DVB_DEVICE_MOD ) ;
break ;
default :
break ;
}
if ( ret < 0 )
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: port_attach on port %d failed \n " , port - > nr ) ;
2015-08-05 17:22:42 +02:00
return ret ;
}
2017-07-10 18:02:59 +02:00
int ddb_ports_attach ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
int i , ret = 0 ;
struct ddb_port * port ;
dev - > ns_num = dev - > link [ 0 ] . info - > ns_num ;
for ( i = 0 ; i < dev - > ns_num ; i + + )
dev - > ns [ i ] . nr = i ;
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: %d netstream channels \n " , dev - > ns_num ) ;
2015-08-05 17:22:42 +02:00
if ( dev - > port_num ) {
ret = dvb_register_adapters ( dev ) ;
if ( ret < 0 ) {
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: Registering adapters failed. Check DVB_MAX_ADAPTERS in config. \n " ) ;
2015-08-05 17:22:42 +02:00
return ret ;
}
}
for ( i = 0 ; i < dev - > port_num ; i + + ) {
port = & dev - > port [ i ] ;
ret = ddb_port_attach ( port ) ;
#if 0
if ( ret < 0 )
break ;
# endif
}
return ret ;
}
2017-07-10 18:02:59 +02:00
void ddb_ports_detach ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
int i ;
struct ddb_port * port ;
for ( i = 0 ; i < dev - > port_num ; i + + ) {
port = & dev - > port [ i ] ;
switch ( port - > class ) {
case DDB_PORT_TUNER :
dvb_input_detach ( port - > input [ 0 ] ) ;
dvb_input_detach ( port - > input [ 1 ] ) ;
break ;
case DDB_PORT_CI :
case DDB_PORT_LOOP :
if ( port - > dvb [ 0 ] . dev )
dvb_unregister_device ( port - > dvb [ 0 ] . dev ) ;
if ( port - > en ) {
dvb_ca_en50221_release ( port - > en ) ;
kfree ( port - > en ) ;
2015-12-13 22:26:35 +01:00
port - > en = NULL ;
2015-08-05 17:22:42 +02:00
}
break ;
case DDB_PORT_MOD :
if ( port - > dvb [ 0 ] . dev )
dvb_unregister_device ( port - > dvb [ 0 ] . dev ) ;
break ;
}
}
dvb_unregister_adapters ( dev ) ;
}
/* Copy input DMA pointers to output DMA and ACK. */
static void input_write_output ( struct ddb_input * input ,
struct ddb_output * output )
{
ddbwritel ( output - > port - > dev ,
2016-05-02 16:27:32 +02:00
input - > dma - > stat , DMA_BUFFER_ACK ( output - > dma ) ) ;
2015-08-05 17:22:42 +02:00
output - > dma - > cbuf = ( input - > dma - > stat > > 11 ) & 0x1f ;
output - > dma - > coff = ( input - > dma - > stat & 0x7ff ) < < 7 ;
}
static void output_ack_input ( struct ddb_output * output ,
struct ddb_input * input )
{
ddbwritel ( input - > port - > dev ,
2016-05-02 16:27:32 +02:00
output - > dma - > stat , DMA_BUFFER_ACK ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
static void input_write_dvb ( struct ddb_input * input ,
struct ddb_input * input2 )
{
struct ddb_dvb * dvb = & input2 - > port - > dvb [ input2 - > nr & 1 ] ;
struct ddb_dma * dma , * dma2 ;
struct ddb * dev = input - > port - > dev ;
int ack = 1 ;
dma = dma2 = input - > dma ;
/* if there also is an output connected, do not ACK.
2017-04-16 21:20:52 +02:00
* input_write_output will ACK .
*/
2015-08-05 17:22:42 +02:00
if ( input - > redo ) {
dma2 = input - > redo - > dma ;
ack = 0 ;
}
while ( dma - > cbuf ! = ( ( dma - > stat > > 11 ) & 0x1f )
| | ( 4 & dma - > ctrl ) ) {
if ( 4 & dma - > ctrl ) {
2016-10-10 00:19:16 +02:00
/*pr_err("DDBridge: Overflow dma %d\n", dma->nr);*/
2015-08-05 17:22:42 +02:00
ack = 1 ;
}
2016-04-15 18:08:51 +02:00
if ( alt_dma )
dma_sync_single_for_cpu ( dev - > dev , dma2 - > pbuf [ dma - > cbuf ] ,
dma2 - > size , DMA_FROM_DEVICE ) ;
2016-05-02 16:27:32 +02:00
#if 0
2017-04-16 21:20:52 +02:00
pr_info ( " DDBridge: %02x %02x %02x %02x \n " ,
2016-05-02 16:27:32 +02:00
dma2 - > vbuf [ dma - > cbuf ] [ 0 ] , dma2 - > vbuf [ dma - > cbuf ] [ 1 ] ,
dma2 - > vbuf [ dma - > cbuf ] [ 2 ] , dma2 - > vbuf [ dma - > cbuf ] [ 3 ] ) ;
# endif
2015-08-05 17:22:42 +02:00
dvb_dmx_swfilter_packets ( & dvb - > demux ,
dma2 - > vbuf [ dma - > cbuf ] ,
dma2 - > size / 188 ) ;
dma - > cbuf = ( dma - > cbuf + 1 ) % dma2 - > num ;
if ( ack )
ddbwritel ( dev , ( dma - > cbuf < < 11 ) ,
2016-05-02 16:27:32 +02:00
DMA_BUFFER_ACK ( dma ) ) ;
dma - > stat = ddbreadl ( dev , DMA_BUFFER_CURRENT ( dma ) ) ;
dma - > ctrl = ddbreadl ( dev , DMA_BUFFER_CONTROL ( dma ) ) ;
2015-08-05 17:22:42 +02:00
}
}
# ifdef DDB_USE_WORK
static void input_work ( struct work_struct * work )
{
struct ddb_dma * dma = container_of ( work , struct ddb_dma , work ) ;
struct ddb_input * input = ( struct ddb_input * ) dma - > io ;
# else
static void input_tasklet ( unsigned long data )
{
struct ddb_input * input = ( struct ddb_input * ) data ;
struct ddb_dma * dma = input - > dma ;
# endif
struct ddb * dev = input - > port - > dev ;
unsigned long flags ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
spin_lock_irqsave ( & dma - > lock , flags ) ;
if ( ! dma - > running ) {
spin_unlock_irqrestore ( & dma - > lock , flags ) ;
return ;
}
2016-05-02 16:27:32 +02:00
dma - > stat = ddbreadl ( dev , DMA_BUFFER_CURRENT ( dma ) ) ;
dma - > ctrl = ddbreadl ( dev , DMA_BUFFER_CONTROL ( dma ) ) ;
2015-08-05 17:22:42 +02:00
#if 0
if ( 4 & dma - > ctrl )
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: Overflow dma %d \n " , dma - > nr ) ;
2015-08-05 17:22:42 +02:00
# endif
if ( input - > redi )
input_write_dvb ( input , input - > redi ) ;
if ( input - > redo )
input_write_output ( input , input - > redo ) ;
wake_up ( & dma - > wq ) ;
spin_unlock_irqrestore ( & dma - > lock , flags ) ;
}
static void input_handler ( unsigned long data )
{
struct ddb_input * input = ( struct ddb_input * ) data ;
struct ddb_dma * dma = input - > dma ;
/* If there is no input connected, input_tasklet() will
2017-04-16 21:20:52 +02:00
* just copy pointers and ACK . So , there is no need to go
* through the tasklet scheduler .
*/
2015-08-05 17:22:42 +02:00
# ifdef DDB_USE_WORK
if ( input - > redi )
queue_work ( ddb_wq , & dma - > work ) ;
else
input_work ( & dma - > work ) ;
# else
if ( input - > redi )
tasklet_schedule ( & dma - > tasklet ) ;
else
input_tasklet ( data ) ;
# endif
}
static void output_handler ( unsigned long data )
{
struct ddb_output * output = ( struct ddb_output * ) data ;
struct ddb_dma * dma = output - > dma ;
struct ddb * dev = output - > port - > dev ;
spin_lock ( & dma - > lock ) ;
if ( ! dma - > running ) {
spin_unlock ( & dma - > lock ) ;
return ;
}
2016-05-02 16:27:32 +02:00
dma - > stat = ddbreadl ( dev , DMA_BUFFER_CURRENT ( dma ) ) ;
dma - > ctrl = ddbreadl ( dev , DMA_BUFFER_CONTROL ( dma ) ) ;
2015-08-05 17:22:42 +02:00
if ( output - > redi )
output_ack_input ( output , output - > redi ) ;
wake_up ( & dma - > wq ) ;
spin_unlock ( & dma - > lock ) ;
}
/****************************************************************************/
/****************************************************************************/
2016-05-02 16:27:32 +02:00
static struct ddb_regmap * io_regmap ( struct ddb_io * io , int link )
2015-08-05 17:22:42 +02:00
{
2016-05-02 16:27:32 +02:00
struct ddb_info * info ;
if ( link )
info = io - > port - > dev - > link [ io - > port - > lnr ] . info ;
else
info = io - > port - > dev - > link [ 0 ] . info ;
if ( ! info )
return NULL ;
return info - > regmap ;
}
static void ddb_dma_init ( struct ddb_io * io , int nr , int out )
{
struct ddb_dma * dma ;
struct ddb_regmap * rm = io_regmap ( io , 0 ) ;
2017-04-16 21:20:52 +02:00
2016-05-02 16:27:32 +02:00
dma = out ? & io - > port - > dev - > odma [ nr ] : & io - > port - > dev - > idma [ nr ] ;
io - > dma = dma ;
2015-08-05 17:22:42 +02:00
dma - > io = io ;
spin_lock_init ( & dma - > lock ) ;
init_waitqueue_head ( & dma - > wq ) ;
if ( out ) {
2016-05-02 16:27:32 +02:00
dma - > regs = rm - > odma - > base + rm - > odma - > size * nr ;
dma - > bufregs = rm - > odma_buf - > base + rm - > odma_buf - > size * nr ;
2017-02-21 17:12:35 +01:00
if ( io - > port - > dev - > link [ 0 ] . info - > type = = DDB_MOD & &
io - > port - > dev - > link [ 0 ] . info - > version = = 3 ) {
dma - > num = OUTPUT_DMA_BUFS_SDR ;
dma - > size = OUTPUT_DMA_SIZE_SDR ;
dma - > div = OUTPUT_DMA_IRQ_DIV_SDR ;
} else {
dma - > num = OUTPUT_DMA_BUFS ;
dma - > size = OUTPUT_DMA_SIZE ;
dma - > div = OUTPUT_DMA_IRQ_DIV ;
}
2015-08-05 17:22:42 +02:00
} else {
# ifdef DDB_USE_WORK
INIT_WORK ( & dma - > work , input_work ) ;
# else
2016-05-02 16:27:32 +02:00
tasklet_init ( & dma - > tasklet , input_tasklet , ( unsigned long ) io ) ;
2015-08-05 17:22:42 +02:00
# endif
2016-05-02 16:27:32 +02:00
dma - > regs = rm - > idma - > base + rm - > idma - > size * nr ;
dma - > bufregs = rm - > idma_buf - > base + rm - > idma_buf - > size * nr ;
2015-08-05 17:22:42 +02:00
dma - > num = INPUT_DMA_BUFS ;
dma - > size = INPUT_DMA_SIZE ;
dma - > div = INPUT_DMA_IRQ_DIV ;
}
2016-05-02 16:27:32 +02:00
ddbwritel ( io - > port - > dev , 0 , DMA_BUFFER_ACK ( dma ) ) ;
2016-10-24 15:13:26 +02:00
pr_debug ( " DDBridge: init link %u, io %u, dma %u, dmaregs %08x bufregs %08x \n " ,
io - > port - > lnr , io - > nr , nr , dma - > regs , dma - > bufregs ) ;
2015-08-05 17:22:42 +02:00
}
2016-05-02 16:27:32 +02:00
static void ddb_input_init ( struct ddb_port * port , int nr , int pnr , int anr )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = port - > dev ;
struct ddb_input * input = & dev - > input [ anr ] ;
2016-05-02 16:27:32 +02:00
struct ddb_regmap * rm ;
2015-08-05 17:22:42 +02:00
port - > input [ pnr ] = input ;
input - > nr = nr ;
input - > port = port ;
2016-05-02 16:27:32 +02:00
rm = io_regmap ( input , 1 ) ;
input - > regs = DDB_LINK_TAG ( port - > lnr ) |
( rm - > input - > base + rm - > input - > size * nr ) ;
2017-04-16 21:20:52 +02:00
pr_debug ( " DDBridge: init link %u, input %u, regs %08x \n " ,
port - > lnr , nr , input - > regs ) ;
2015-08-05 17:22:42 +02:00
if ( dev - > has_dma ) {
2016-05-06 12:32:25 +02:00
struct ddb_regmap * rm0 = io_regmap ( input , 0 ) ;
u32 base = rm0 - > irq_base_idma ;
2016-05-02 16:27:32 +02:00
u32 dma_nr = nr ;
if ( port - > lnr )
dma_nr + = 32 + ( port - > lnr - 1 ) * 8 ;
2017-04-16 21:20:52 +02:00
2016-10-24 15:13:26 +02:00
pr_debug ( " DDBridge: init link %u, input %u, handler %u \n " ,
2017-04-16 21:20:52 +02:00
port - > lnr , nr , dma_nr + base ) ;
2016-05-02 16:27:32 +02:00
dev - > handler [ 0 ] [ dma_nr + base ] = input_handler ;
dev - > handler_data [ 0 ] [ dma_nr + base ] = ( unsigned long ) input ;
ddb_dma_init ( input , dma_nr , 0 ) ;
2015-08-05 17:22:42 +02:00
}
}
2016-05-02 16:27:32 +02:00
static void ddb_output_init ( struct ddb_port * port , int nr )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = port - > dev ;
struct ddb_output * output = & dev - > output [ nr ] ;
2016-05-02 16:27:32 +02:00
struct ddb_regmap * rm ;
2015-08-05 17:22:42 +02:00
port - > output = output ;
output - > nr = nr ;
output - > port = port ;
2016-05-02 16:27:32 +02:00
rm = io_regmap ( output , 1 ) ;
output - > regs = DDB_LINK_TAG ( port - > lnr ) |
( rm - > output - > base + rm - > output - > size * nr ) ;
2016-10-24 15:13:26 +02:00
pr_debug ( " DDBridge: init link %u, output %u, regs %08x \n " ,
2017-04-16 21:20:52 +02:00
port - > lnr , nr , output - > regs ) ;
2015-08-05 17:22:42 +02:00
if ( dev - > has_dma ) {
2016-05-06 12:32:25 +02:00
struct ddb_regmap * rm0 = io_regmap ( output , 0 ) ;
u32 base = rm0 - > irq_base_odma ;
2016-05-02 16:27:32 +02:00
dev - > handler [ 0 ] [ nr + base ] = output_handler ;
dev - > handler_data [ 0 ] [ nr + base ] = ( unsigned long ) output ;
ddb_dma_init ( output , nr , 1 ) ;
2015-08-05 17:22:42 +02:00
}
}
static int ddb_port_match_i2c ( struct ddb_port * port )
{
struct ddb * dev = port - > dev ;
u32 i ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
for ( i = 0 ; i < dev - > i2c_num ; i + + ) {
if ( dev - > i2c [ i ] . link = = port - > lnr & &
dev - > i2c [ i ] . nr = = port - > nr ) {
port - > i2c = & dev - > i2c [ i ] ;
return 1 ;
}
}
return 0 ;
}
2016-05-02 16:27:32 +02:00
static int ddb_port_match_link_i2c ( struct ddb_port * port )
{
struct ddb * dev = port - > dev ;
u32 i ;
for ( i = 0 ; i < dev - > i2c_num ; i + + ) {
if ( dev - > i2c [ i ] . link = = port - > lnr ) {
port - > i2c = & dev - > i2c [ i ] ;
return 1 ;
}
}
return 0 ;
}
2017-07-10 18:02:59 +02:00
void ddb_ports_init ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
2016-05-02 16:27:32 +02:00
u32 i , l , p ;
2015-08-05 17:22:42 +02:00
struct ddb_port * port ;
struct ddb_info * info ;
struct ddb_regmap * rm ;
for ( p = l = 0 ; l < DDB_MAX_LINK ; l + + ) {
info = dev - > link [ l ] . info ;
if ( ! info )
continue ;
rm = info - > regmap ;
if ( ! rm )
continue ;
for ( i = 0 ; i < info - > port_num ; i + + , p + + ) {
port = & dev - > port [ p ] ;
port - > dev = dev ;
port - > nr = i ;
port - > lnr = l ;
port - > pnr = p ;
2016-06-27 23:01:21 +02:00
port - > gap = 0xffffffff ;
2015-08-05 17:22:42 +02:00
port - > obr = ci_bitrate ;
mutex_init ( & port - > i2c_gate_lock ) ;
2016-05-02 16:27:32 +02:00
if ( ! ddb_port_match_i2c ( port ) )
2015-08-05 17:22:42 +02:00
if ( info - > type = = DDB_OCTOPUS_MAX )
2016-05-02 16:27:32 +02:00
ddb_port_match_link_i2c ( port ) ;
2015-08-05 17:22:42 +02:00
ddb_port_probe ( port ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
port - > dvb [ 0 ] . adap = & dev - > adap [ 2 * p ] ;
port - > dvb [ 1 ] . adap = & dev - > adap [ 2 * p + 1 ] ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( ( port - > class = = DDB_PORT_NONE ) & & i & &
dev - > port [ p - 1 ] . type = = DDB_CI_EXTERNAL_XO2 ) {
port - > class = DDB_PORT_CI ;
port - > type = DDB_CI_EXTERNAL_XO2_B ;
port - > name = " DuoFlex CI_B " ;
port - > i2c = dev - > port [ p - 1 ] . i2c ;
}
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: Port %u: Link %u, Link Port %u (TAB %u): %s \n " ,
2016-03-24 12:10:20 +01:00
port - > pnr , port - > lnr , port - > nr ,
port - > nr + 1 , port - > name ) ;
2015-08-05 17:22:42 +02:00
if ( port - > class = = DDB_PORT_CI & &
port - > type = = DDB_CI_EXTERNAL_XO2 ) {
2016-05-02 16:27:32 +02:00
ddb_input_init ( port , 2 * i , 0 , 2 * i ) ;
ddb_output_init ( port , i ) ;
2015-08-05 17:22:42 +02:00
continue ;
}
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( port - > class = = DDB_PORT_CI & &
port - > type = = DDB_CI_EXTERNAL_XO2_B ) {
2016-05-02 16:27:32 +02:00
ddb_input_init ( port , 2 * i - 1 , 0 , 2 * i - 1 ) ;
ddb_output_init ( port , i ) ;
2015-08-05 17:22:42 +02:00
continue ;
}
2016-05-02 16:27:32 +02:00
if ( port - > class = = DDB_PORT_NONE )
continue ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
switch ( dev - > link [ l ] . info - > type ) {
case DDB_OCTOPUS_CI :
if ( i > = 2 ) {
2016-05-02 16:27:32 +02:00
ddb_input_init ( port , 2 + i , 0 , 2 + i ) ;
ddb_input_init ( port , 4 + i , 1 , 4 + i ) ;
ddb_output_init ( port , i ) ;
2015-08-05 17:22:42 +02:00
break ;
} /* fallthrough */
case DDB_OCTONET :
case DDB_OCTOPUS :
2016-04-15 23:53:20 +02:00
case DDB_OCTOPRO :
2016-05-02 16:27:32 +02:00
ddb_input_init ( port , 2 * i , 0 , 2 * i ) ;
ddb_input_init ( port , 2 * i + 1 , 1 , 2 * i + 1 ) ;
ddb_output_init ( port , i ) ;
2015-08-05 17:22:42 +02:00
break ;
case DDB_OCTOPUS_MAX :
2015-09-17 18:54:25 +02:00
case DDB_OCTOPUS_MAX_CT :
2016-05-02 16:27:32 +02:00
ddb_input_init ( port , 2 * i , 0 , 2 * p ) ;
ddb_input_init ( port , 2 * i + 1 , 1 , 2 * p + 1 ) ;
2015-08-05 17:22:42 +02:00
break ;
case DDB_MOD :
2016-05-02 16:27:32 +02:00
ddb_output_init ( port , i ) ;
2016-07-31 21:41:03 +02:00
dev - > handler [ 0 ] [ i + rm - > irq_base_rate ] =
2016-03-24 12:10:20 +01:00
ddbridge_mod_rate_handler ;
2016-07-31 21:41:03 +02:00
dev - > handler_data [ 0 ] [ i + rm - > irq_base_rate ] =
2015-08-05 17:22:42 +02:00
( unsigned long ) & dev - > output [ i ] ;
break ;
default :
break ;
}
}
}
dev - > port_num = p ;
}
2017-07-10 18:02:59 +02:00
void ddb_ports_release ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
int i ;
struct ddb_port * port ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
for ( i = 0 ; i < dev - > port_num ; i + + ) {
port = & dev - > port [ i ] ;
# ifdef DDB_USE_WORK
if ( port - > input [ 0 ] & & port - > input [ 0 ] - > dma )
cancel_work_sync ( & port - > input [ 0 ] - > dma - > work ) ;
if ( port - > input [ 1 ] & & port - > input [ 1 ] - > dma )
cancel_work_sync ( & port - > input [ 1 ] - > dma - > work ) ;
if ( port - > output & & port - > output - > dma )
cancel_work_sync ( & port - > output - > dma - > work ) ;
# else
if ( port - > input [ 0 ] & & port - > input [ 0 ] - > dma )
tasklet_kill ( & port - > input [ 0 ] - > dma - > tasklet ) ;
if ( port - > input [ 1 ] & & port - > input [ 1 ] - > dma )
tasklet_kill ( & port - > input [ 1 ] - > dma - > tasklet ) ;
if ( port - > output & & port - > output - > dma )
tasklet_kill ( & port - > output - > dma - > tasklet ) ;
# endif
}
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
# define IRQ_HANDLE(_nr) \
2016-04-15 23:53:20 +02:00
do { if ( ( s & ( 1UL < < ( ( _nr ) & 0x1f ) ) ) & & dev - > handler [ 0 ] [ _nr ] ) \
2016-04-15 18:08:51 +02:00
dev - > handler [ 0 ] [ _nr ] ( dev - > handler_data [ 0 ] [ _nr ] ) ; } \
2015-08-05 17:22:42 +02:00
while ( 0 )
2017-04-16 21:20:52 +02:00
# define IRQ_HANDLE_BYTE(_n) { \
if ( s & ( 0x000000ff < < ( ( _n ) & 0x1f ) ) ) { \
IRQ_HANDLE ( 0 + ( _n ) ) ; \
IRQ_HANDLE ( 1 + ( _n ) ) ; \
IRQ_HANDLE ( 2 + ( _n ) ) ; \
IRQ_HANDLE ( 3 + ( _n ) ) ; \
IRQ_HANDLE ( 4 + ( _n ) ) ; \
IRQ_HANDLE ( 5 + ( _n ) ) ; \
IRQ_HANDLE ( 6 + ( _n ) ) ; \
IRQ_HANDLE ( 7 + ( _n ) ) ; \
} \
2016-04-15 22:45:55 +02:00
}
2015-08-05 17:22:42 +02:00
static void irq_handle_msg ( struct ddb * dev , u32 s )
{
dev - > i2c_irq + + ;
IRQ_HANDLE ( 0 ) ;
IRQ_HANDLE ( 1 ) ;
IRQ_HANDLE ( 2 ) ;
IRQ_HANDLE ( 3 ) ;
}
static void irq_handle_io ( struct ddb * dev , u32 s )
{
dev - > ts_irq + + ;
if ( ( s & 0x000000f0 ) ) {
IRQ_HANDLE ( 4 ) ;
IRQ_HANDLE ( 5 ) ;
IRQ_HANDLE ( 6 ) ;
IRQ_HANDLE ( 7 ) ;
}
if ( ( s & 0x0000ff00 ) ) {
IRQ_HANDLE ( 8 ) ;
IRQ_HANDLE ( 9 ) ;
IRQ_HANDLE ( 10 ) ;
IRQ_HANDLE ( 11 ) ;
IRQ_HANDLE ( 12 ) ;
IRQ_HANDLE ( 13 ) ;
IRQ_HANDLE ( 14 ) ;
IRQ_HANDLE ( 15 ) ;
}
if ( ( s & 0x00ff0000 ) ) {
IRQ_HANDLE ( 16 ) ;
IRQ_HANDLE ( 17 ) ;
IRQ_HANDLE ( 18 ) ;
IRQ_HANDLE ( 19 ) ;
IRQ_HANDLE ( 20 ) ;
IRQ_HANDLE ( 21 ) ;
IRQ_HANDLE ( 22 ) ;
IRQ_HANDLE ( 23 ) ;
}
if ( ( s & 0xff000000 ) ) {
IRQ_HANDLE ( 24 ) ;
IRQ_HANDLE ( 25 ) ;
IRQ_HANDLE ( 26 ) ;
IRQ_HANDLE ( 27 ) ;
IRQ_HANDLE ( 28 ) ;
IRQ_HANDLE ( 29 ) ;
IRQ_HANDLE ( 30 ) ;
IRQ_HANDLE ( 31 ) ;
}
}
2017-07-10 18:02:59 +02:00
irqreturn_t irq_handler0 ( int irq , void * dev_id )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = ( struct ddb * ) dev_id ;
u32 s = ddbreadl ( dev , INTERRUPT_STATUS ) ;
do {
2016-04-13 11:31:30 +02:00
if ( s & 0x80000000 )
2015-08-05 17:22:42 +02:00
return IRQ_NONE ;
2017-03-10 12:29:11 +01:00
if ( ! ( s & 0xfffff00 ) )
2015-08-05 17:22:42 +02:00
return IRQ_NONE ;
2017-03-10 12:29:11 +01:00
ddbwritel ( dev , s & 0xfffff00 , INTERRUPT_ACK ) ;
2015-08-05 17:22:42 +02:00
irq_handle_io ( dev , s ) ;
} while ( ( s = ddbreadl ( dev , INTERRUPT_STATUS ) ) ) ;
return IRQ_HANDLED ;
}
2017-07-10 18:02:59 +02:00
irqreturn_t irq_handler1 ( int irq , void * dev_id )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = ( struct ddb * ) dev_id ;
u32 s = ddbreadl ( dev , INTERRUPT_STATUS ) ;
do {
if ( s & 0x80000000 )
return IRQ_NONE ;
if ( ! ( s & 0x0000f ) )
return IRQ_NONE ;
2016-04-13 11:31:30 +02:00
ddbwritel ( dev , s & 0x0000f , INTERRUPT_ACK ) ;
2015-08-05 17:22:42 +02:00
irq_handle_msg ( dev , s ) ;
} while ( ( s = ddbreadl ( dev , INTERRUPT_STATUS ) ) ) ;
return IRQ_HANDLED ;
}
2017-07-10 18:02:59 +02:00
irqreturn_t irq_handler ( int irq , void * dev_id )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = ( struct ddb * ) dev_id ;
u32 s = ddbreadl ( dev , INTERRUPT_STATUS ) ;
int ret = IRQ_HANDLED ;
if ( ! s )
return IRQ_NONE ;
do {
if ( s & 0x80000000 )
return IRQ_NONE ;
ddbwritel ( dev , s , INTERRUPT_ACK ) ;
if ( s & 0x0000000f )
irq_handle_msg ( dev , s ) ;
if ( s & 0x0fffff00 ) {
irq_handle_io ( dev , s ) ;
# ifdef DDB_TEST_THREADED
ret = IRQ_WAKE_THREAD ;
# endif
}
} while ( ( s = ddbreadl ( dev , INTERRUPT_STATUS ) ) ) ;
return ret ;
}
2017-07-10 18:02:59 +02:00
irqreturn_t irq_handle_v2_n ( struct ddb * dev , u32 n )
2016-04-15 18:08:51 +02:00
{
2016-05-02 16:27:32 +02:00
u32 reg = INTERRUPT_V2_STATUS + 4 * n ;
2016-04-15 18:08:51 +02:00
u32 s = ddbreadl ( dev , reg ) ;
u32 off = n * 32 ;
2016-04-15 23:53:20 +02:00
2016-04-15 18:08:51 +02:00
if ( ! s )
return IRQ_NONE ;
ddbwritel ( dev , s , reg ) ;
2017-04-16 21:20:52 +02:00
2016-04-15 18:08:51 +02:00
if ( ( s & 0x000000ff ) ) {
2017-04-16 21:20:52 +02:00
IRQ_HANDLE ( 0 + off ) ;
IRQ_HANDLE ( 1 + off ) ;
IRQ_HANDLE ( 2 + off ) ;
IRQ_HANDLE ( 3 + off ) ;
IRQ_HANDLE ( 4 + off ) ;
IRQ_HANDLE ( 5 + off ) ;
IRQ_HANDLE ( 6 + off ) ;
IRQ_HANDLE ( 7 + off ) ;
2016-05-02 16:27:32 +02:00
}
if ( ( s & 0x0000ff00 ) ) {
2017-04-16 21:20:52 +02:00
IRQ_HANDLE ( 8 + off ) ;
IRQ_HANDLE ( 9 + off ) ;
2016-05-02 16:27:32 +02:00
IRQ_HANDLE ( 10 + off ) ;
IRQ_HANDLE ( 11 + off ) ;
IRQ_HANDLE ( 12 + off ) ;
IRQ_HANDLE ( 13 + off ) ;
IRQ_HANDLE ( 14 + off ) ;
IRQ_HANDLE ( 15 + off ) ;
}
if ( ( s & 0x00ff0000 ) ) {
IRQ_HANDLE ( 16 + off ) ;
IRQ_HANDLE ( 17 + off ) ;
IRQ_HANDLE ( 18 + off ) ;
IRQ_HANDLE ( 19 + off ) ;
IRQ_HANDLE ( 20 + off ) ;
IRQ_HANDLE ( 21 + off ) ;
IRQ_HANDLE ( 22 + off ) ;
IRQ_HANDLE ( 23 + off ) ;
}
if ( ( s & 0xff000000 ) ) {
IRQ_HANDLE ( 24 + off ) ;
IRQ_HANDLE ( 25 + off ) ;
IRQ_HANDLE ( 26 + off ) ;
IRQ_HANDLE ( 27 + off ) ;
IRQ_HANDLE ( 28 + off ) ;
IRQ_HANDLE ( 29 + off ) ;
IRQ_HANDLE ( 30 + off ) ;
IRQ_HANDLE ( 31 + off ) ;
2016-04-15 18:08:51 +02:00
}
2016-04-15 22:45:55 +02:00
return IRQ_HANDLED ;
2016-04-15 18:08:51 +02:00
}
2017-07-10 18:02:59 +02:00
irqreturn_t irq_handler_v2 ( int irq , void * dev_id )
2016-04-15 18:08:51 +02:00
{
struct ddb * dev = ( struct ddb * ) dev_id ;
2016-04-15 23:53:20 +02:00
u32 s = 0xffff & ddbreadl ( dev , INTERRUPT_V2_STATUS ) ;
2016-04-15 18:08:51 +02:00
int ret = IRQ_HANDLED ;
if ( ! s )
return IRQ_NONE ;
do {
2016-05-02 16:27:32 +02:00
if ( s & 0x80 )
2016-04-15 18:08:51 +02:00
return IRQ_NONE ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , s , INTERRUPT_V2_STATUS ) ;
2016-04-15 18:08:51 +02:00
if ( s & 0x00000001 )
2016-05-02 16:27:32 +02:00
irq_handle_v2_n ( dev , 1 ) ;
2016-05-05 00:15:02 +02:00
if ( s & 0x00000002 )
2016-05-02 16:27:32 +02:00
irq_handle_v2_n ( dev , 2 ) ;
if ( s & 0x00000004 )
irq_handle_v2_n ( dev , 3 ) ;
IRQ_HANDLE ( 8 ) ;
IRQ_HANDLE ( 9 ) ;
IRQ_HANDLE ( 10 ) ;
IRQ_HANDLE ( 11 ) ;
2016-04-15 23:53:20 +02:00
} while ( ( s = 0xffff & ddbreadl ( dev , INTERRUPT_V2_STATUS ) ) ) ;
2016-04-15 18:08:51 +02:00
return ret ;
}
2015-08-05 17:22:42 +02:00
# ifdef DDB_TEST_THREADED
2017-07-10 18:02:59 +02:00
irqreturn_t irq_thread ( int irq , void * dev_id )
2015-08-05 17:22:42 +02:00
{
/* struct ddb *dev = (struct ddb *) dev_id; */
2016-10-10 00:19:16 +02:00
/*pr_info("DDBridge: %s\n", __func__);*/
2015-08-05 17:22:42 +02:00
return IRQ_HANDLED ;
}
# endif
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static ssize_t nsd_read ( struct file * file , char * buf ,
size_t count , loff_t * ppos )
{
return 0 ;
}
static unsigned int nsd_poll ( struct file * file , poll_table * wait )
{
return 0 ;
}
static int nsd_release ( struct inode * inode , struct file * file )
{
return dvb_generic_release ( inode , file ) ;
}
static int nsd_open ( struct inode * inode , struct file * file )
{
return dvb_generic_open ( inode , file ) ;
}
static struct ddb_input * plugtoinput ( struct ddb * dev , u8 plug )
{
int i , j ;
for ( i = j = 0 ; i < dev - > port_num ; i + + ) {
if ( dev - > port [ i ] . class = = DDB_PORT_TUNER ) {
if ( j = = plug )
return dev - > port [ i ] . input [ 0 ] ;
if ( j + 1 = = plug )
return dev - > port [ i ] . input [ 1 ] ;
j + = 2 ;
}
}
return 0 ;
}
static int nsd_do_ioctl ( struct file * file , unsigned int cmd , void * parg )
{
struct dvb_device * dvbdev = file - > private_data ;
struct ddb * dev = dvbdev - > priv ;
/* unsigned long arg = (unsigned long) parg; */
int ret = 0 ;
switch ( cmd ) {
case NSD_START_GET_TS :
{
struct dvb_nsd_ts * ts = parg ;
struct ddb_input * input = plugtoinput ( dev , ts - > input ) ;
u32 ctrl ;
u32 to ;
if ( ! input )
return - EINVAL ;
ctrl = ( input - > port - > lnr < < 16 ) | ( ( input - > nr & 7 ) < < 8 ) |
( ( ts - > filter_mask & 3 ) < < 2 ) ;
2017-04-16 21:20:52 +02:00
2015-08-05 17:22:42 +02:00
if ( ddbreadl ( dev , TS_CAPTURE_CONTROL ) & 1 ) {
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: ts capture busy \n " ) ;
2015-08-05 17:22:42 +02:00
return - EBUSY ;
}
ddb_dvb_ns_input_start ( input ) ;
ddbwritel ( dev , ctrl , TS_CAPTURE_CONTROL ) ;
ddbwritel ( dev , ts - > pid , TS_CAPTURE_PID ) ;
ddbwritel ( dev , ( ts - > section_id < < 16 ) |
( ts - > table < < 8 ) | ts - > section ,
TS_CAPTURE_TABLESECTION ) ;
/* 1024 ms default timeout if timeout set to 0 */
if ( ts - > timeout )
to = ts - > timeout ;
else
to = 1024 ;
/* 21 packets default if num set to 0 */
if ( ts - > num )
to | = ( ( u32 ) ts - > num < < 16 ) ;
else
to | = ( 21 < < 16 ) ;
ddbwritel ( dev , to , TS_CAPTURE_TIMEOUT ) ;
if ( ts - > mode )
ctrl | = 2 ;
ddbwritel ( dev , ctrl | 1 , TS_CAPTURE_CONTROL ) ;
break ;
}
case NSD_POLL_GET_TS :
{
struct dvb_nsd_ts * ts = parg ;
u32 ctrl = ddbreadl ( dev , TS_CAPTURE_CONTROL ) ;
if ( ctrl & 1 )
return - EBUSY ;
if ( ctrl & ( 1 < < 14 ) ) {
2016-10-10 00:19:16 +02:00
/*pr_info("DDBridge: ts capture timeout\n");*/
2015-08-05 17:22:42 +02:00
return - EAGAIN ;
}
ddbcpyfrom ( dev , dev - > tsbuf , TS_CAPTURE_MEMORY ,
TS_CAPTURE_LEN ) ;
ts - > len = ddbreadl ( dev , TS_CAPTURE_RECEIVED ) & 0x1fff ;
if ( copy_to_user ( ts - > ts , dev - > tsbuf , ts - > len ) )
return - EIO ;
break ;
}
case NSD_CANCEL_GET_TS :
{
u32 ctrl = 0 ;
2016-03-24 12:10:20 +01:00
2016-10-10 00:19:16 +02:00
/*pr_info("DDBridge: cancel ts capture: 0x%x\n", ctrl);*/
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , ctrl , TS_CAPTURE_CONTROL ) ;
ctrl = ddbreadl ( dev , TS_CAPTURE_CONTROL ) ;
2016-10-10 00:19:16 +02:00
/*pr_info("DDBridge: control register is 0x%x\n", ctrl);*/
2015-08-05 17:22:42 +02:00
break ;
}
case NSD_STOP_GET_TS :
{
struct dvb_nsd_ts * ts = parg ;
struct ddb_input * input = plugtoinput ( dev , ts - > input ) ;
u32 ctrl = ddbreadl ( dev , TS_CAPTURE_CONTROL ) ;
if ( ! input )
return - EINVAL ;
if ( ctrl & 1 ) {
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: cannot stop ts capture, while it was neither finished nor canceled \n " ) ;
2015-08-05 17:22:42 +02:00
return - EBUSY ;
}
2016-10-10 00:19:16 +02:00
/*pr_info("DDBridge: ts capture stopped\n");*/
2015-08-05 17:22:42 +02:00
ddb_dvb_ns_input_stop ( input ) ;
break ;
}
default :
ret = - EINVAL ;
break ;
}
return ret ;
}
static long nsd_ioctl ( struct file * file ,
unsigned int cmd , unsigned long arg )
{
return dvb_usercopy ( file , cmd , arg , nsd_do_ioctl ) ;
}
static const struct file_operations nsd_fops = {
. owner = THIS_MODULE ,
. read = nsd_read ,
. open = nsd_open ,
. release = nsd_release ,
. poll = nsd_poll ,
. unlocked_ioctl = nsd_ioctl ,
} ;
static struct dvb_device dvbdev_nsd = {
. priv = 0 ,
. readers = 1 ,
. writers = 1 ,
. users = 1 ,
. fops = & nsd_fops ,
} ;
static int ddb_nsd_attach ( struct ddb * dev )
{
int ret ;
if ( ! dev - > link [ 0 ] . info - > ns_num )
return 0 ;
ret = dvb_register_device ( & dev - > adap [ 0 ] ,
& dev - > nsd_dev ,
& dvbdev_nsd , ( void * ) dev ,
DVB_DEVICE_NSD ) ;
return ret ;
}
2017-07-10 18:02:59 +02:00
void ddb_nsd_detach ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
if ( ! dev - > link [ 0 ] . info - > ns_num )
return ;
if ( dev - > nsd_dev - > users > 2 ) {
wait_event ( dev - > nsd_dev - > wait_queue ,
dev - > nsd_dev - > users = = 2 ) ;
}
dvb_unregister_device ( dev - > nsd_dev ) ;
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static int reg_wait ( struct ddb * dev , u32 reg , u32 bit )
{
u32 count = 0 ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
while ( ddbreadl ( dev , reg ) & bit ) {
ndelay ( 10 ) ;
if ( + + count = = 100 )
return - 1 ;
}
return 0 ;
}
2016-03-24 12:10:20 +01:00
static int flashio ( struct ddb * dev , u32 lnr ,
u8 * wbuf , u32 wlen , u8 * rbuf , u32 rlen )
2015-08-05 17:22:42 +02:00
{
u32 data , shift ;
u32 tag = DDB_LINK_TAG ( lnr ) ;
struct ddb_link * link = & dev - > link [ lnr ] ;
mutex_lock ( & link - > flash_mutex ) ;
if ( wlen > 4 )
ddbwritel ( dev , 1 , tag | SPI_CONTROL ) ;
while ( wlen > 4 ) {
/* FIXME: check for big-endian */
data = swab32 ( * ( u32 * ) wbuf ) ;
wbuf + = 4 ;
wlen - = 4 ;
ddbwritel ( dev , data , tag | SPI_DATA ) ;
if ( reg_wait ( dev , tag | SPI_CONTROL , 4 ) )
goto fail ;
}
if ( rlen )
ddbwritel ( dev , 0x0001 | ( ( wlen < < ( 8 + 3 ) ) & 0x1f00 ) ,
tag | SPI_CONTROL ) ;
else
ddbwritel ( dev , 0x0003 | ( ( wlen < < ( 8 + 3 ) ) & 0x1f00 ) ,
tag | SPI_CONTROL ) ;
data = 0 ;
shift = ( ( 4 - wlen ) * 8 ) ;
while ( wlen ) {
data < < = 8 ;
data | = * wbuf ;
wlen - - ;
wbuf + + ;
}
if ( shift )
data < < = shift ;
ddbwritel ( dev , data , tag | SPI_DATA ) ;
if ( reg_wait ( dev , tag | SPI_CONTROL , 4 ) )
goto fail ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( ! rlen ) {
ddbwritel ( dev , 0 , tag | SPI_CONTROL ) ;
goto exit ;
}
if ( rlen > 4 )
ddbwritel ( dev , 1 , tag | SPI_CONTROL ) ;
while ( rlen > 4 ) {
ddbwritel ( dev , 0xffffffff , tag | SPI_DATA ) ;
if ( reg_wait ( dev , tag | SPI_CONTROL , 4 ) )
goto fail ;
data = ddbreadl ( dev , tag | SPI_DATA ) ;
* ( u32 * ) rbuf = swab32 ( data ) ;
rbuf + = 4 ;
rlen - = 4 ;
}
2016-03-24 12:10:20 +01:00
ddbwritel ( dev , 0x0003 | ( ( rlen < < ( 8 + 3 ) ) & 0x1F00 ) ,
tag | SPI_CONTROL ) ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , 0xffffffff , tag | SPI_DATA ) ;
if ( reg_wait ( dev , tag | SPI_CONTROL , 4 ) )
goto fail ;
data = ddbreadl ( dev , tag | SPI_DATA ) ;
ddbwritel ( dev , 0 , tag | SPI_CONTROL ) ;
if ( rlen < 4 )
data < < = ( ( 4 - rlen ) * 8 ) ;
while ( rlen > 0 ) {
* rbuf = ( ( data > > 24 ) & 0xff ) ;
data < < = 8 ;
rbuf + + ;
rlen - - ;
}
exit :
mutex_unlock ( & link - > flash_mutex ) ;
return 0 ;
fail :
mutex_unlock ( & link - > flash_mutex ) ;
return - 1 ;
}
int ddbridge_flashread ( struct ddb * dev , u32 link , u8 * buf , u32 addr , u32 len )
{
u8 cmd [ 4 ] = { 0x03 , ( addr > > 16 ) & 0xff ,
( addr > > 8 ) & 0xff , addr & 0xff } ;
return flashio ( dev , link , cmd , 4 , buf , len ) ;
}
static int mdio_write ( struct ddb * dev , u8 adr , u8 reg , u16 val )
{
ddbwritel ( dev , adr , MDIO_ADR ) ;
ddbwritel ( dev , reg , MDIO_REG ) ;
ddbwritel ( dev , val , MDIO_VAL ) ;
ddbwritel ( dev , 0x03 , MDIO_CTRL ) ;
while ( ddbreadl ( dev , MDIO_CTRL ) & 0x02 )
ndelay ( 500 ) ;
return 0 ;
}
static u16 mdio_read ( struct ddb * dev , u8 adr , u8 reg )
{
ddbwritel ( dev , adr , MDIO_ADR ) ;
ddbwritel ( dev , reg , MDIO_REG ) ;
ddbwritel ( dev , 0x07 , MDIO_CTRL ) ;
while ( ddbreadl ( dev , MDIO_CTRL ) & 0x02 )
ndelay ( 500 ) ;
return ddbreadl ( dev , MDIO_VAL ) ;
}
# define DDB_MAGIC 'd'
struct ddb_flashio {
__u8 * write_buf ;
__u32 write_len ;
__u8 * read_buf ;
__u32 read_len ;
__u32 link ;
} ;
struct ddb_gpio {
__u32 mask ;
__u32 data ;
} ;
struct ddb_id {
__u16 vendor ;
__u16 device ;
__u16 subvendor ;
__u16 subdevice ;
__u32 hw ;
__u32 regmap ;
} ;
struct ddb_reg {
__u32 reg ;
__u32 val ;
} ;
struct ddb_mem {
__u32 off ;
__u8 * buf ;
__u32 len ;
} ;
struct ddb_mdio {
__u8 adr ;
__u8 reg ;
__u16 val ;
} ;
struct ddb_i2c_msg {
__u8 bus ;
__u8 adr ;
__u8 * hdr ;
__u32 hlen ;
__u8 * msg ;
__u32 mlen ;
} ;
# define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio)
# define IOCTL_DDB_GPIO_IN _IOWR(DDB_MAGIC, 0x01, struct ddb_gpio)
# define IOCTL_DDB_GPIO_OUT _IOWR(DDB_MAGIC, 0x02, struct ddb_gpio)
# define IOCTL_DDB_ID _IOR(DDB_MAGIC, 0x03, struct ddb_id)
# define IOCTL_DDB_READ_REG _IOWR(DDB_MAGIC, 0x04, struct ddb_reg)
# define IOCTL_DDB_WRITE_REG _IOW(DDB_MAGIC, 0x05, struct ddb_reg)
# define IOCTL_DDB_READ_MEM _IOWR(DDB_MAGIC, 0x06, struct ddb_mem)
# define IOCTL_DDB_WRITE_MEM _IOR(DDB_MAGIC, 0x07, struct ddb_mem)
# define IOCTL_DDB_READ_MDIO _IOWR(DDB_MAGIC, 0x08, struct ddb_mdio)
# define IOCTL_DDB_WRITE_MDIO _IOR(DDB_MAGIC, 0x09, struct ddb_mdio)
# define IOCTL_DDB_READ_I2C _IOWR(DDB_MAGIC, 0x0a, struct ddb_i2c_msg)
# define IOCTL_DDB_WRITE_I2C _IOR(DDB_MAGIC, 0x0b, struct ddb_i2c_msg)
# define DDB_NAME "ddbridge"
static u32 ddb_num ;
static int ddb_major ;
static DEFINE_MUTEX ( ddb_mutex ) ;
static int ddb_release ( struct inode * inode , struct file * file )
{
struct ddb * dev = file - > private_data ;
dev - > ddb_dev_users - - ;
return 0 ;
}
static int ddb_open ( struct inode * inode , struct file * file )
{
struct ddb * dev = ddbs [ iminor ( inode ) ] ;
if ( dev - > ddb_dev_users )
return - EBUSY ;
dev - > ddb_dev_users + + ;
file - > private_data = dev ;
return 0 ;
}
static long ddb_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
{
struct ddb * dev = file - > private_data ;
void * parg = ( void * ) arg ;
int res ;
switch ( cmd ) {
case IOCTL_DDB_FLASHIO :
{
struct ddb_flashio fio ;
u8 * rbuf , * wbuf ;
if ( copy_from_user ( & fio , parg , sizeof ( fio ) ) )
return - EFAULT ;
if ( fio . write_len > 1028 | | fio . read_len > 1028 )
return - EINVAL ;
if ( fio . write_len + fio . read_len > 1028 )
return - EINVAL ;
if ( fio . link > 3 )
return - EINVAL ;
wbuf = & dev - > iobuf [ 0 ] ;
rbuf = wbuf + fio . write_len ;
if ( copy_from_user ( wbuf , fio . write_buf , fio . write_len ) )
return - EFAULT ;
2016-03-24 12:10:20 +01:00
res = flashio ( dev , fio . link , wbuf ,
fio . write_len , rbuf , fio . read_len ) ;
2015-08-05 17:22:42 +02:00
if ( res )
return res ;
if ( copy_to_user ( fio . read_buf , rbuf , fio . read_len ) )
return - EFAULT ;
break ;
}
case IOCTL_DDB_GPIO_OUT :
{
struct ddb_gpio gpio ;
if ( copy_from_user ( & gpio , parg , sizeof ( gpio ) ) )
return - EFAULT ;
ddbwritel ( dev , gpio . mask , GPIO_DIRECTION ) ;
ddbwritel ( dev , gpio . data , GPIO_OUTPUT ) ;
break ;
}
case IOCTL_DDB_ID :
{
struct ddb_id ddbid ;
2015-09-06 19:08:57 +02:00
ddbid . vendor = dev - > link [ 0 ] . ids . vendor ;
ddbid . device = dev - > link [ 0 ] . ids . device ;
ddbid . subvendor = dev - > link [ 0 ] . ids . subvendor ;
ddbid . subdevice = dev - > link [ 0 ] . ids . subdevice ;
2015-08-05 17:22:42 +02:00
ddbid . hw = ddbreadl ( dev , 0 ) ;
ddbid . regmap = ddbreadl ( dev , 4 ) ;
if ( copy_to_user ( parg , & ddbid , sizeof ( ddbid ) ) )
return - EFAULT ;
break ;
}
case IOCTL_DDB_READ_REG :
{
struct ddb_reg reg ;
if ( copy_from_user ( & reg , parg , sizeof ( reg ) ) )
return - EFAULT ;
if ( ( reg . reg & 0xfffffff ) > = dev - > regs_len )
return - EINVAL ;
reg . val = ddbreadl ( dev , reg . reg ) ;
if ( copy_to_user ( parg , & reg , sizeof ( reg ) ) )
return - EFAULT ;
break ;
}
case IOCTL_DDB_WRITE_REG :
{
struct ddb_reg reg ;
if ( copy_from_user ( & reg , parg , sizeof ( reg ) ) )
return - EFAULT ;
if ( ( reg . reg & 0xfffffff ) > = dev - > regs_len )
return - EINVAL ;
ddbwritel ( dev , reg . val , reg . reg ) ;
break ;
}
case IOCTL_DDB_READ_MDIO :
{
struct ddb_mdio mdio ;
if ( ! dev - > link [ 0 ] . info - > mdio_num )
return - EIO ;
if ( copy_from_user ( & mdio , parg , sizeof ( mdio ) ) )
return - EFAULT ;
mdio . val = mdio_read ( dev , mdio . adr , mdio . reg ) ;
if ( copy_to_user ( parg , & mdio , sizeof ( mdio ) ) )
return - EFAULT ;
break ;
}
case IOCTL_DDB_WRITE_MDIO :
{
struct ddb_mdio mdio ;
if ( ! dev - > link [ 0 ] . info - > mdio_num )
return - EIO ;
if ( copy_from_user ( & mdio , parg , sizeof ( mdio ) ) )
return - EFAULT ;
mdio_write ( dev , mdio . adr , mdio . reg , mdio . val ) ;
break ;
}
case IOCTL_DDB_READ_MEM :
{
struct ddb_mem mem ;
u8 * buf = & dev - > iobuf [ 0 ] ;
if ( copy_from_user ( & mem , parg , sizeof ( mem ) ) )
return - EFAULT ;
if ( ( ( ( mem . len + mem . off ) & 0xfffffff ) > dev - > regs_len ) | |
mem . len > 1024 )
return - EINVAL ;
ddbcpyfrom ( dev , buf , mem . off , mem . len ) ;
if ( copy_to_user ( mem . buf , buf , mem . len ) )
return - EFAULT ;
break ;
}
case IOCTL_DDB_WRITE_MEM :
{
struct ddb_mem mem ;
u8 * buf = & dev - > iobuf [ 0 ] ;
if ( copy_from_user ( & mem , parg , sizeof ( mem ) ) )
return - EFAULT ;
if ( ( ( ( mem . len + mem . off ) & 0xfffffff ) > dev - > regs_len ) | |
mem . len > 1024 )
return - EINVAL ;
if ( copy_from_user ( buf , mem . buf , mem . len ) )
return - EFAULT ;
ddbcpyto ( dev , mem . off , buf , mem . len ) ;
break ;
}
case IOCTL_DDB_READ_I2C :
{
struct ddb_i2c_msg i2c ;
struct i2c_adapter * adap ;
u8 * mbuf , * hbuf = & dev - > iobuf [ 0 ] ;
if ( copy_from_user ( & i2c , parg , sizeof ( i2c ) ) )
return - EFAULT ;
if ( i2c . bus > dev - > link [ 0 ] . info - > regmap - > i2c - > num )
return - EINVAL ;
if ( i2c . mlen + i2c . hlen > 512 )
return - EINVAL ;
adap = & dev - > i2c [ i2c . bus ] . adap ;
mbuf = hbuf + i2c . hlen ;
if ( copy_from_user ( hbuf , i2c . hdr , i2c . hlen ) )
return - EFAULT ;
if ( i2c_io ( adap , i2c . adr , hbuf , i2c . hlen , mbuf , i2c . mlen ) < 0 )
return - EIO ;
if ( copy_to_user ( i2c . msg , mbuf , i2c . mlen ) )
return - EFAULT ;
break ;
}
case IOCTL_DDB_WRITE_I2C :
{
struct ddb_i2c_msg i2c ;
struct i2c_adapter * adap ;
u8 * buf = & dev - > iobuf [ 0 ] ;
if ( copy_from_user ( & i2c , parg , sizeof ( i2c ) ) )
return - EFAULT ;
if ( i2c . bus > dev - > link [ 0 ] . info - > regmap - > i2c - > num )
return - EINVAL ;
if ( i2c . mlen + i2c . hlen > 250 )
return - EINVAL ;
adap = & dev - > i2c [ i2c . bus ] . adap ;
if ( copy_from_user ( buf , i2c . hdr , i2c . hlen ) )
return - EFAULT ;
if ( copy_from_user ( buf + i2c . hlen , i2c . msg , i2c . mlen ) )
return - EFAULT ;
if ( i2c_write ( adap , i2c . adr , buf , i2c . hlen + i2c . mlen ) < 0 )
return - EIO ;
break ;
}
default :
return - ENOTTY ;
}
return 0 ;
}
static const struct file_operations ddb_fops = {
. unlocked_ioctl = ddb_ioctl ,
. open = ddb_open ,
. release = ddb_release ,
} ;
# if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
static char * ddb_devnode ( struct device * device , mode_t * mode )
# else
static char * ddb_devnode ( struct device * device , umode_t * mode )
# endif
{
struct ddb * dev = dev_get_drvdata ( device ) ;
return kasprintf ( GFP_KERNEL , " ddbridge/card%d " , dev - > nr ) ;
}
# define __ATTR_MRO(_name, _show) { \
. attr = { . name = __stringify ( _name ) , . mode = 0444 } , \
. show = _show , \
}
# define __ATTR_MWO(_name, _store) { \
. attr = { . name = __stringify ( _name ) , . mode = 0222 } , \
. store = _store , \
}
static ssize_t ports_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
2016-05-05 00:15:02 +02:00
return sprintf ( buf , " %d \n " , dev - > port_num ) ;
2015-08-05 17:22:42 +02:00
}
static ssize_t ts_irq_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
return sprintf ( buf , " %d \n " , dev - > ts_irq ) ;
}
static ssize_t i2c_irq_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
return sprintf ( buf , " %d \n " , dev - > i2c_irq ) ;
}
static char * class_name [ ] = {
" NONE " , " CI " , " TUNER " , " LOOP " , " MOD "
} ;
static ssize_t fan_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
u32 val ;
val = ddbreadl ( dev , GPIO_OUTPUT ) & 1 ;
return sprintf ( buf , " %d \n " , val ) ;
}
static ssize_t fan_store ( struct device * device , struct device_attribute * d ,
const char * buf , size_t count )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
2017-04-16 21:20:52 +02:00
u32 val ;
2015-08-05 17:22:42 +02:00
if ( sscanf ( buf , " %u \n " , & val ) ! = 1 )
return - EINVAL ;
ddbwritel ( dev , 1 , GPIO_DIRECTION ) ;
ddbwritel ( dev , val & 1 , GPIO_OUTPUT ) ;
return count ;
}
2016-08-29 18:44:53 +02:00
static ssize_t fanspeed_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 8 ] - 0x30 ;
struct ddb_link * link = & dev - > link [ num ] ;
u32 spd ;
spd = ddblreadl ( link , TEMPMON_FANCONTROL ) & 0xff ;
return sprintf ( buf , " %u \n " , spd * 100 ) ;
}
2015-08-05 17:22:42 +02:00
static ssize_t temp_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
2016-08-29 18:44:53 +02:00
struct ddb_link * link = & dev - > link [ 0 ] ;
2015-08-05 17:22:42 +02:00
struct i2c_adapter * adap ;
2016-08-02 21:22:18 +02:00
s32 temp , temp2 , temp3 ;
int i ;
2015-08-05 17:22:42 +02:00
u8 tmp [ 2 ] ;
2017-04-16 21:20:52 +02:00
2017-02-09 10:12:43 +01:00
if ( link - > info - > type = = DDB_MOD ) {
if ( link - > info - > version > = 2 ) {
2016-12-14 19:24:58 +01:00
temp = 0xffff & ddbreadl ( dev , TEMPMON2_BOARD ) ;
2016-08-02 21:22:18 +02:00
temp = ( temp * 1000 ) > > 8 ;
2016-12-14 19:24:58 +01:00
temp2 = 0xffff & ddbreadl ( dev , TEMPMON2_FPGACORE ) ;
2016-08-02 21:22:18 +02:00
temp2 = ( temp2 * 1000 ) > > 8 ;
2016-12-14 19:24:58 +01:00
temp3 = 0xffff & ddbreadl ( dev , TEMPMON2_QAMCORE ) ;
2016-08-02 21:22:18 +02:00
temp3 = ( temp3 * 1000 ) > > 8 ;
2017-04-16 21:20:52 +02:00
2016-08-02 21:22:18 +02:00
return sprintf ( buf , " %d %d %d \n " , temp , temp2 , temp3 ) ;
}
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , 1 , TEMPMON_CONTROL ) ;
for ( i = 0 ; i < 10 ; i + + ) {
if ( 0 = = ( 1 & ddbreadl ( dev , TEMPMON_CONTROL ) ) )
break ;
usleep_range ( 1000 , 2000 ) ;
}
temp = ddbreadl ( dev , TEMPMON_SENSOR1 ) ;
temp2 = ddbreadl ( dev , TEMPMON_SENSOR2 ) ;
temp = ( temp * 1000 ) > > 8 ;
temp2 = ( temp2 * 1000 ) > > 8 ;
if ( ddbreadl ( dev , TEMPMON_CONTROL ) & 0x8000 ) {
temp3 = ddbreadl ( dev , TEMPMON_CORE ) ;
temp3 = ( temp3 * 1000 ) > > 8 ;
return sprintf ( buf , " %d %d %d \n " , temp , temp2 , temp3 ) ;
}
return sprintf ( buf , " %d %d \n " , temp , temp2 ) ;
}
2017-02-09 10:12:43 +01:00
if ( ! link - > info - > temp_num )
2015-08-05 17:22:42 +02:00
return sprintf ( buf , " no sensor \n " ) ;
2017-02-09 10:12:43 +01:00
adap = & dev - > i2c [ link - > info - > temp_bus ] . adap ;
2015-08-05 17:22:42 +02:00
if ( i2c_read_regs ( adap , 0x48 , 0 , tmp , 2 ) < 0 )
return sprintf ( buf , " read_error \n " ) ;
temp = ( tmp [ 0 ] < < 3 ) | ( tmp [ 1 ] > > 5 ) ;
temp * = 125 ;
2017-02-09 10:12:43 +01:00
if ( link - > info - > temp_num = = 2 ) {
2015-08-05 17:22:42 +02:00
if ( i2c_read_regs ( adap , 0x49 , 0 , tmp , 2 ) < 0 )
return sprintf ( buf , " read_error \n " ) ;
temp2 = ( tmp [ 0 ] < < 3 ) | ( tmp [ 1 ] > > 5 ) ;
temp2 * = 125 ;
return sprintf ( buf , " %d %d \n " , temp , temp2 ) ;
}
return sprintf ( buf , " %d \n " , temp ) ;
}
static ssize_t ctemp_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
struct i2c_adapter * adap ;
int temp ;
u8 tmp [ 2 ] ;
int num = attr - > attr . name [ 4 ] - 0x30 ;
adap = & dev - > i2c [ num ] . adap ;
if ( ! adap )
return 0 ;
if ( i2c_read_regs ( adap , 0x49 , 0 , tmp , 2 ) < 0 )
if ( i2c_read_regs ( adap , 0x4d , 0 , tmp , 2 ) < 0 )
return sprintf ( buf , " no sensor \n " ) ;
temp = tmp [ 0 ] * 1000 ;
return sprintf ( buf , " %d \n " , temp ) ;
}
#if 0
static ssize_t qam_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
struct i2c_adapter * adap ;
u8 tmp [ 4 ] ;
s16 i , q ;
adap = & dev - > i2c [ 1 ] . adap ;
if ( i2c_read_regs16 ( adap , 0x1f , 0xf480 , tmp , 4 ) < 0 )
return sprintf ( buf , " read_error \n " ) ;
i = ( s16 ) ( ( ( u16 ) tmp [ 1 ] ) < < 14 ) | ( ( ( u16 ) tmp [ 0 ] ) < < 6 ) ;
q = ( s16 ) ( ( ( u16 ) tmp [ 3 ] ) < < 14 ) | ( ( ( u16 ) tmp [ 2 ] ) < < 6 ) ;
return sprintf ( buf , " %d %d \n " , i , q ) ;
}
# endif
static ssize_t mod_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
return sprintf ( buf , " %s:%s \n " ,
class_name [ dev - > port [ num ] . class ] ,
2015-10-22 14:51:36 +02:00
dev - > port [ num ] . type_name ) ;
2015-08-05 17:22:42 +02:00
}
static ssize_t led_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
return sprintf ( buf , " %d \n " , dev - > leds & ( 1 < < num ) ? 1 : 0 ) ;
}
static void ddb_set_led ( struct ddb * dev , int num , int val )
{
if ( ! dev - > link [ 0 ] . info - > led_num )
return ;
switch ( dev - > port [ num ] . class ) {
case DDB_PORT_TUNER :
switch ( dev - > port [ num ] . type ) {
case DDB_TUNER_DVBS_ST :
i2c_write_reg16 ( & dev - > i2c [ num ] . adap ,
0x69 , 0xf14c , val ? 2 : 0 ) ;
break ;
case DDB_TUNER_DVBCT_ST :
i2c_write_reg16 ( & dev - > i2c [ num ] . adap ,
0x1f , 0xf00e , 0 ) ;
i2c_write_reg16 ( & dev - > i2c [ num ] . adap ,
0x1f , 0xf00f , val ? 1 : 0 ) ;
break ;
2016-11-07 21:19:53 +01:00
case DDB_TUNER_XO2 . . . DDB_TUNER_DVBC2T2I_SONY :
2015-08-05 17:22:42 +02:00
{
u8 v ;
i2c_read_reg ( & dev - > i2c [ num ] . adap , 0x10 , 0x08 , & v ) ;
v = ( v & ~ 0x10 ) | ( val ? 0x10 : 0 ) ;
i2c_write_reg ( & dev - > i2c [ num ] . adap , 0x10 , 0x08 , v ) ;
break ;
}
default :
break ;
}
break ;
}
}
static ssize_t led_store ( struct device * device ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
2017-04-16 21:20:52 +02:00
u32 val ;
2015-08-05 17:22:42 +02:00
if ( sscanf ( buf , " %u \n " , & val ) ! = 1 )
return - EINVAL ;
if ( val )
dev - > leds | = ( 1 < < num ) ;
else
dev - > leds & = ~ ( 1 < < num ) ;
ddb_set_led ( dev , num , val ) ;
return count ;
}
static ssize_t snr_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
char snr [ 32 ] ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
if ( dev - > port [ num ] . type > = DDB_TUNER_XO2 ) {
if ( i2c_read_regs ( & dev - > i2c [ num ] . adap , 0x10 , 0x10 , snr , 16 ) < 0 )
return sprintf ( buf , " NO SNR \n " ) ;
snr [ 16 ] = 0 ;
} else {
/* serial number at 0x100-0x11f */
if ( i2c_read_regs16 ( & dev - > i2c [ num ] . adap ,
0x57 , 0x100 , snr , 32 ) < 0 )
if ( i2c_read_regs16 ( & dev - > i2c [ num ] . adap ,
0x50 , 0x100 , snr , 32 ) < 0 )
return sprintf ( buf , " NO SNR \n " ) ;
snr [ 31 ] = 0 ; /* in case it is not terminated on EEPROM */
}
return sprintf ( buf , " %s \n " , snr ) ;
}
static ssize_t snr_store ( struct device * device , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
u8 snr [ 34 ] = { 0x01 , 0x00 } ;
return 0 ; /* NOE: remove completely? */
if ( count > 31 )
return - EINVAL ;
if ( dev - > port [ num ] . type > = DDB_TUNER_XO2 )
return - EINVAL ;
memcpy ( snr + 2 , buf , count ) ;
i2c_write ( & dev - > i2c [ num ] . adap , 0x57 , snr , 34 ) ;
i2c_write ( & dev - > i2c [ num ] . adap , 0x50 , snr , 34 ) ;
return count ;
}
static ssize_t bsnr_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
char snr [ 16 ] ;
ddbridge_flashread ( dev , 0 , snr , 0x10 , 15 ) ;
snr [ 15 ] = 0 ; /* in case it is not terminated on EEPROM */
return sprintf ( buf , " %s \n " , snr ) ;
}
static ssize_t bpsnr_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
char snr [ 32 ] ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( ! dev - > i2c_num )
return 0 ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( i2c_read_regs16 ( & dev - > i2c [ 0 ] . adap ,
0x50 , 0x0000 , snr , 32 ) < 0 | |
2016-03-24 12:10:20 +01:00
snr [ 0 ] = = 0xff )
2015-08-05 17:22:42 +02:00
return sprintf ( buf , " NO SNR \n " ) ;
snr [ 31 ] = 0 ; /* in case it is not terminated on EEPROM */
return sprintf ( buf , " %s \n " , snr ) ;
}
static ssize_t redirect_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
return 0 ;
}
static ssize_t redirect_store ( struct device * device ,
struct device_attribute * attr ,
2016-05-31 16:53:04 +02:00
const char * buf , size_t count )
{
unsigned int i , p ;
int res ;
if ( sscanf ( buf , " %x %x \n " , & i , & p ) ! = 2 )
return - EINVAL ;
res = ddb_redirect ( i , p ) ;
if ( res < 0 )
return res ;
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: redirect: %02x, %02x \n " , i , p ) ;
2016-05-31 16:53:04 +02:00
return count ;
}
2017-02-21 17:12:35 +01:00
#if 0
2016-05-31 16:53:04 +02:00
/* A L P I AAAAAALLPPPPPPII */
/* AAAAAAAA LLLLLLLL PPPPPPII */
static ssize_t redirect2_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
return 0 ;
}
static ssize_t redirect2_store ( struct device * device ,
struct device_attribute * attr ,
2015-08-05 17:22:42 +02:00
const char * buf , size_t count )
{
unsigned int i , p ;
int res ;
if ( sscanf ( buf , " %x %x \n " , & i , & p ) ! = 2 )
return - EINVAL ;
res = ddb_redirect ( i , p ) ;
if ( res < 0 )
return res ;
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: redirect: %02x, %02x \n " , i , p ) ;
2015-08-05 17:22:42 +02:00
return count ;
}
2017-02-21 17:12:35 +01:00
# endif
2015-08-05 17:22:42 +02:00
static ssize_t gap_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
return sprintf ( buf , " %d \n " , dev - > port [ num ] . gap ) ;
}
static ssize_t gap_store ( struct device * device , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
unsigned int val ;
if ( sscanf ( buf , " %u \n " , & val ) ! = 1 )
return - EINVAL ;
if ( val > 20 )
return - EINVAL ;
dev - > port [ num ] . gap = val ;
return count ;
}
2016-06-27 23:01:21 +02:00
static ssize_t obr_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
2017-04-16 21:20:52 +02:00
2016-06-27 23:01:21 +02:00
return sprintf ( buf , " %d \n " , dev - > port [ num ] . obr ) ;
}
static ssize_t obr_store ( struct device * device , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
unsigned int val ;
2017-04-16 21:20:52 +02:00
2016-06-27 23:01:21 +02:00
if ( sscanf ( buf , " %u \n " , & val ) ! = 1 )
return - EINVAL ;
if ( val > 96000 )
return - EINVAL ;
dev - > port [ num ] . obr = val ;
return count ;
}
2015-08-05 17:22:42 +02:00
static ssize_t version_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
return sprintf ( buf , " %08x %08x \n " ,
2015-09-06 19:08:57 +02:00
dev - > link [ 0 ] . ids . hwid , dev - > link [ 0 ] . ids . regmapid ) ;
2015-08-05 17:22:42 +02:00
}
static ssize_t hwid_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
2015-09-06 19:08:57 +02:00
return sprintf ( buf , " 0x%08X \n " , dev - > link [ 0 ] . ids . hwid ) ;
2015-08-05 17:22:42 +02:00
}
static ssize_t regmap_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
2015-09-06 19:08:57 +02:00
return sprintf ( buf , " 0x%08X \n " , dev - > link [ 0 ] . ids . regmapid ) ;
2015-08-05 17:22:42 +02:00
}
static ssize_t vlan_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
return sprintf ( buf , " %u \n " , dev - > vlan ) ;
}
static ssize_t vlan_store ( struct device * device , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
unsigned int val ;
if ( sscanf ( buf , " %u \n " , & val ) ! = 1 )
return - EINVAL ;
if ( val > 1 )
return - EINVAL ;
if ( ! dev - > link [ 0 ] . info - > ns_num )
return - EINVAL ;
ddbwritel ( dev , 14 + ( val ? 4 : 0 ) , ETHER_LENGTH ) ;
dev - > vlan = val ;
return count ;
}
static ssize_t fmode_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
int num = attr - > attr . name [ 5 ] - 0x30 ;
struct ddb * dev = dev_get_drvdata ( device ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
return sprintf ( buf , " %u \n " , dev - > link [ num ] . lnb . fmode ) ;
}
2015-09-06 19:08:57 +02:00
static ssize_t devid_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
int num = attr - > attr . name [ 5 ] - 0x30 ;
struct ddb * dev = dev_get_drvdata ( device ) ;
2016-03-24 12:10:20 +01:00
2015-09-06 19:08:57 +02:00
return sprintf ( buf , " %08x \n " , dev - > link [ num ] . ids . devid ) ;
}
2015-08-05 17:22:42 +02:00
static ssize_t fmode_store ( struct device * device , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 5 ] - 0x30 ;
unsigned int val ;
if ( sscanf ( buf , " %u \n " , & val ) ! = 1 )
return - EINVAL ;
if ( val > 3 )
return - EINVAL ;
2015-08-31 20:53:22 +02:00
lnb_init_fmode ( dev , & dev - > link [ num ] , val ) ;
2015-08-05 17:22:42 +02:00
return count ;
}
static struct device_attribute ddb_attrs [ ] = {
__ATTR_RO ( version ) ,
__ATTR_RO ( ports ) ,
__ATTR_RO ( ts_irq ) ,
__ATTR_RO ( i2c_irq ) ,
__ATTR ( gap0 , 0664 , gap_show , gap_store ) ,
__ATTR ( gap1 , 0664 , gap_show , gap_store ) ,
__ATTR ( gap2 , 0664 , gap_show , gap_store ) ,
__ATTR ( gap3 , 0664 , gap_show , gap_store ) ,
2016-06-27 23:01:21 +02:00
__ATTR ( obr0 , 0664 , obr_show , obr_store ) ,
__ATTR ( obr1 , 0664 , obr_show , obr_store ) ,
__ATTR ( obr2 , 0664 , obr_show , obr_store ) ,
__ATTR ( obr3 , 0664 , obr_show , obr_store ) ,
2015-08-05 17:22:42 +02:00
__ATTR ( vlan , 0664 , vlan_show , vlan_store ) ,
__ATTR ( fmode0 , 0664 , fmode_show , fmode_store ) ,
__ATTR ( fmode1 , 0664 , fmode_show , fmode_store ) ,
__ATTR ( fmode2 , 0664 , fmode_show , fmode_store ) ,
__ATTR ( fmode3 , 0664 , fmode_show , fmode_store ) ,
2015-09-06 19:08:57 +02:00
__ATTR_MRO ( devid0 , devid_show ) ,
__ATTR_MRO ( devid1 , devid_show ) ,
__ATTR_MRO ( devid2 , devid_show ) ,
__ATTR_MRO ( devid3 , devid_show ) ,
2015-08-05 17:22:42 +02:00
__ATTR_RO ( hwid ) ,
__ATTR_RO ( regmap ) ,
#if 0
__ATTR_RO ( qam ) ,
# endif
__ATTR ( redirect , 0664 , redirect_show , redirect_store ) ,
__ATTR_MRO ( snr , bsnr_show ) ,
__ATTR_RO ( bpsnr ) ,
__ATTR_NULL ,
} ;
static struct device_attribute ddb_attrs_temp [ ] = {
__ATTR_RO ( temp ) ,
} ;
static struct device_attribute ddb_attrs_mod [ ] = {
__ATTR_MRO ( mod0 , mod_show ) ,
__ATTR_MRO ( mod1 , mod_show ) ,
__ATTR_MRO ( mod2 , mod_show ) ,
__ATTR_MRO ( mod3 , mod_show ) ,
__ATTR_MRO ( mod4 , mod_show ) ,
__ATTR_MRO ( mod5 , mod_show ) ,
__ATTR_MRO ( mod6 , mod_show ) ,
__ATTR_MRO ( mod7 , mod_show ) ,
__ATTR_MRO ( mod8 , mod_show ) ,
__ATTR_MRO ( mod9 , mod_show ) ,
} ;
static struct device_attribute ddb_attrs_fan [ ] = {
__ATTR ( fan , 0664 , fan_show , fan_store ) ,
} ;
static struct device_attribute ddb_attrs_snr [ ] = {
__ATTR ( snr0 , 0664 , snr_show , snr_store ) ,
__ATTR ( snr1 , 0664 , snr_show , snr_store ) ,
__ATTR ( snr2 , 0664 , snr_show , snr_store ) ,
__ATTR ( snr3 , 0664 , snr_show , snr_store ) ,
} ;
static struct device_attribute ddb_attrs_ctemp [ ] = {
__ATTR_MRO ( temp0 , ctemp_show ) ,
__ATTR_MRO ( temp1 , ctemp_show ) ,
__ATTR_MRO ( temp2 , ctemp_show ) ,
__ATTR_MRO ( temp3 , ctemp_show ) ,
} ;
static struct device_attribute ddb_attrs_led [ ] = {
__ATTR ( led0 , 0664 , led_show , led_store ) ,
__ATTR ( led1 , 0664 , led_show , led_store ) ,
__ATTR ( led2 , 0664 , led_show , led_store ) ,
__ATTR ( led3 , 0664 , led_show , led_store ) ,
} ;
2016-08-29 18:44:53 +02:00
static struct device_attribute ddb_attrs_fanspeed [ ] = {
__ATTR_MRO ( fanspeed0 , fanspeed_show ) ,
__ATTR_MRO ( fanspeed1 , fanspeed_show ) ,
__ATTR_MRO ( fanspeed2 , fanspeed_show ) ,
__ATTR_MRO ( fanspeed3 , fanspeed_show ) ,
} ;
2015-08-05 17:22:42 +02:00
static struct class ddb_class = {
. name = " ddbridge " ,
. owner = THIS_MODULE ,
#if 0
. dev_attrs = ddb_attrs ,
# endif
. devnode = ddb_devnode ,
} ;
2017-07-10 18:02:59 +02:00
int ddb_class_create ( void )
2015-08-05 17:22:42 +02:00
{
ddb_major = register_chrdev ( 0 , DDB_NAME , & ddb_fops ) ;
if ( ddb_major < 0 )
return ddb_major ;
if ( class_register ( & ddb_class ) < 0 )
return - 1 ;
return 0 ;
}
2017-07-10 18:02:59 +02:00
void ddb_class_destroy ( void )
2015-08-05 17:22:42 +02:00
{
class_unregister ( & ddb_class ) ;
unregister_chrdev ( ddb_major , DDB_NAME ) ;
}
static void ddb_device_attrs_del ( struct ddb * dev )
{
int i ;
2016-08-29 18:44:53 +02:00
for ( i = 0 ; i < 4 ; i + + )
2016-08-29 21:13:48 +02:00
if ( dev - > link [ i ] . info & &
dev - > link [ i ] . info - > tempmon_irq )
2017-04-16 21:20:52 +02:00
device_remove_file ( dev - > ddb_dev ,
& ddb_attrs_fanspeed [ i ] ) ;
2015-08-05 17:22:42 +02:00
for ( i = 0 ; i < dev - > link [ 0 ] . info - > temp_num ; i + + )
device_remove_file ( dev - > ddb_dev , & ddb_attrs_temp [ i ] ) ;
for ( i = 0 ; i < dev - > link [ 0 ] . info - > port_num ; i + + )
device_remove_file ( dev - > ddb_dev , & ddb_attrs_mod [ i ] ) ;
for ( i = 0 ; i < dev - > link [ 0 ] . info - > fan_num ; i + + )
device_remove_file ( dev - > ddb_dev , & ddb_attrs_fan [ i ] ) ;
for ( i = 0 ; i < dev - > i2c_num & & i < 4 ; i + + ) {
if ( dev - > link [ 0 ] . info - > led_num )
device_remove_file ( dev - > ddb_dev , & ddb_attrs_led [ i ] ) ;
device_remove_file ( dev - > ddb_dev , & ddb_attrs_snr [ i ] ) ;
device_remove_file ( dev - > ddb_dev , & ddb_attrs_ctemp [ i ] ) ;
}
2016-07-31 21:41:03 +02:00
for ( i = 0 ; ddb_attrs [ i ] . attr . name ! = NULL ; i + + )
2015-08-05 17:22:42 +02:00
device_remove_file ( dev - > ddb_dev , & ddb_attrs [ i ] ) ;
}
static int ddb_device_attrs_add ( struct ddb * dev )
{
int i ;
2016-07-31 21:41:03 +02:00
for ( i = 0 ; ddb_attrs [ i ] . attr . name ! = NULL ; i + + )
2015-08-05 17:22:42 +02:00
if ( device_create_file ( dev - > ddb_dev , & ddb_attrs [ i ] ) )
goto fail ;
for ( i = 0 ; i < dev - > link [ 0 ] . info - > temp_num ; i + + )
if ( device_create_file ( dev - > ddb_dev , & ddb_attrs_temp [ i ] ) )
goto fail ;
2016-07-31 21:41:03 +02:00
for ( i = 0 ; ( i < dev - > link [ 0 ] . info - > port_num ) & & ( i < 10 ) ; i + + )
2015-08-05 17:22:42 +02:00
if ( device_create_file ( dev - > ddb_dev , & ddb_attrs_mod [ i ] ) )
goto fail ;
for ( i = 0 ; i < dev - > link [ 0 ] . info - > fan_num ; i + + )
if ( device_create_file ( dev - > ddb_dev , & ddb_attrs_fan [ i ] ) )
goto fail ;
2016-07-31 21:41:03 +02:00
for ( i = 0 ; ( i < dev - > i2c_num ) & & ( i < 4 ) ; i + + ) {
2015-08-05 17:22:42 +02:00
if ( device_create_file ( dev - > ddb_dev , & ddb_attrs_snr [ i ] ) )
goto fail ;
if ( device_create_file ( dev - > ddb_dev , & ddb_attrs_ctemp [ i ] ) )
goto fail ;
if ( dev - > link [ 0 ] . info - > led_num )
if ( device_create_file ( dev - > ddb_dev ,
& ddb_attrs_led [ i ] ) )
goto fail ;
}
2016-08-29 18:44:53 +02:00
for ( i = 0 ; i < 4 ; i + + )
if ( dev - > link [ i ] . info & &
dev - > link [ i ] . info - > tempmon_irq )
if ( device_create_file ( dev - > ddb_dev ,
& ddb_attrs_fanspeed [ i ] ) )
goto fail ;
2015-08-05 17:22:42 +02:00
return 0 ;
fail :
return - 1 ;
}
2017-07-10 18:02:59 +02:00
int ddb_device_create ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
int res = 0 ;
if ( ddb_num = = DDB_MAX_ADAPTER )
return - ENOMEM ;
mutex_lock ( & ddb_mutex ) ;
dev - > nr = ddb_num ;
ddbs [ dev - > nr ] = dev ;
dev - > ddb_dev = device_create ( & ddb_class , dev - > dev ,
MKDEV ( ddb_major , dev - > nr ) ,
dev , " ddbridge%d " , dev - > nr ) ;
if ( IS_ERR ( dev - > ddb_dev ) ) {
res = PTR_ERR ( dev - > ddb_dev ) ;
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: Could not create ddbridge%d \n " , dev - > nr ) ;
2015-08-05 17:22:42 +02:00
goto fail ;
}
res = ddb_device_attrs_add ( dev ) ;
if ( res ) {
ddb_device_attrs_del ( dev ) ;
device_destroy ( & ddb_class , MKDEV ( ddb_major , dev - > nr ) ) ;
ddbs [ dev - > nr ] = 0 ;
dev - > ddb_dev = ERR_PTR ( - ENODEV ) ;
} else
ddb_num + + ;
fail :
mutex_unlock ( & ddb_mutex ) ;
return res ;
}
2017-07-10 18:02:59 +02:00
void ddb_device_destroy ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
if ( IS_ERR ( dev - > ddb_dev ) )
return ;
ddb_device_attrs_del ( dev ) ;
device_destroy ( & ddb_class , MKDEV ( ddb_major , dev - > nr ) ) ;
}
2016-04-15 18:08:51 +02:00
# define LINK_IRQ_HANDLE(_l, _nr) \
do { if ( ( s & ( 1UL < < _nr ) ) & & dev - > handler [ _l ] [ _nr ] ) \
dev - > handler [ _l ] [ _nr ] ( dev - > handler_data [ _l ] [ _nr ] ) ; } \
2015-08-05 17:22:42 +02:00
while ( 0 )
static void gtl_link_handler ( unsigned long priv )
{
2015-08-31 20:53:22 +02:00
struct ddb * dev = ( struct ddb * ) priv ;
u32 regs = dev - > link [ 0 ] . info - > regmap - > gtl - > base ;
2016-03-24 12:10:20 +01:00
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: GT link change: %u \n " ,
2016-03-24 12:10:20 +01:00
( 1 & ddbreadl ( dev , regs ) ) ) ;
2015-08-05 17:22:42 +02:00
}
static void link_tasklet ( unsigned long data )
{
struct ddb_link * link = ( struct ddb_link * ) data ;
struct ddb * dev = link - > dev ;
2016-04-15 18:08:51 +02:00
u32 s , tag = DDB_LINK_TAG ( link - > nr ) ;
u32 l = link - > nr ;
2017-04-16 21:20:52 +02:00
2015-08-05 17:22:42 +02:00
s = ddbreadl ( dev , tag | INTERRUPT_STATUS ) ;
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: gtl_irq %08x = %08x \n " , tag | INTERRUPT_STATUS , s ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( ! s )
return ;
ddbwritel ( dev , s , tag | INTERRUPT_ACK ) ;
2016-04-15 18:08:51 +02:00
LINK_IRQ_HANDLE ( l , 0 ) ;
LINK_IRQ_HANDLE ( l , 1 ) ;
LINK_IRQ_HANDLE ( l , 2 ) ;
LINK_IRQ_HANDLE ( l , 3 ) ;
2016-08-29 18:44:53 +02:00
LINK_IRQ_HANDLE ( l , 24 ) ;
2015-08-05 17:22:42 +02:00
}
static void gtl_irq_handler ( unsigned long priv )
{
struct ddb_link * link = ( struct ddb_link * ) priv ;
# if 1
struct ddb * dev = link - > dev ;
2016-04-15 18:08:51 +02:00
u32 s , l = link - > nr , tag = DDB_LINK_TAG ( link - > nr ) ;
2016-03-24 12:10:20 +01:00
2015-09-20 01:45:11 +02:00
while ( ( s = ddbreadl ( dev , tag | INTERRUPT_STATUS ) ) ) {
ddbwritel ( dev , s , tag | INTERRUPT_ACK ) ;
2016-10-10 00:19:16 +02:00
//pr_info("DDBridge: gtlirq %08x\n", s);
2016-04-15 18:08:51 +02:00
LINK_IRQ_HANDLE ( l , 0 ) ;
LINK_IRQ_HANDLE ( l , 1 ) ;
LINK_IRQ_HANDLE ( l , 2 ) ;
LINK_IRQ_HANDLE ( l , 3 ) ;
2016-08-29 18:44:53 +02:00
LINK_IRQ_HANDLE ( l , 24 ) ;
2015-09-20 01:45:11 +02:00
}
2015-08-05 17:22:42 +02:00
# else
tasklet_schedule ( & link - > tasklet ) ;
# endif
}
static int ddb_gtl_init_link ( struct ddb * dev , u32 l )
{
struct ddb_link * link = & dev - > link [ l ] ;
u32 regs = dev - > link [ 0 ] . info - > regmap - > gtl - > base +
( l - 1 ) * dev - > link [ 0 ] . info - > regmap - > gtl - > size ;
2016-10-10 00:19:16 +02:00
u32 id , subid , base = dev - > link [ 0 ] . info - > regmap - > irq_base_gtl ;
2016-03-24 12:10:20 +01:00
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: Checking GT link %u: regs = %08x \n " , l , regs ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
spin_lock_init ( & link - > lock ) ;
mutex_init ( & link - > lnb . lock ) ;
2015-08-31 20:53:22 +02:00
link - > lnb . fmode = 0xffffffff ;
2015-08-05 17:22:42 +02:00
mutex_init ( & link - > flash_mutex ) ;
2016-05-03 22:05:29 +02:00
link - > nr = l ;
link - > dev = dev ;
link - > regs = regs ;
2015-08-05 17:22:42 +02:00
if ( ! ( 1 & ddbreadl ( dev , regs ) ) ) {
u32 c ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
for ( c = 0 ; c < 5 ; c + + ) {
ddbwritel ( dev , 2 , regs ) ;
msleep ( 20 ) ;
ddbwritel ( dev , 0 , regs ) ;
msleep ( 200 ) ;
if ( 1 & ddbreadl ( dev , regs ) )
break ;
}
if ( c = = 5 )
return - 1 ;
}
id = ddbreadl ( dev , DDB_LINK_TAG ( l ) | 8 ) ;
2016-10-10 00:19:16 +02:00
subid = ddbreadl ( dev , DDB_LINK_TAG ( l ) | 12 ) ;
2015-09-17 18:54:25 +02:00
switch ( id ) {
case 0x0007dd01 :
2016-05-02 16:27:32 +02:00
link - > info = & ddb_s2_48 ;
2015-09-17 18:54:25 +02:00
break ;
case 0x0008dd01 :
2017-04-07 22:22:06 +02:00
switch ( subid ) {
case 0x0035dd01 :
default :
link - > info = & ddb_c2t2_8 ;
break ;
case 0x0036dd01 :
link - > info = & ddb_isdbt_8 ;
break ;
case 0x0037dd01 :
link - > info = & ddb_c2t2i_v0_8 ;
break ;
case 0x0038dd01 :
link - > info = & ddb_c2t2i_8 ;
break ;
}
2015-09-17 18:54:25 +02:00
break ;
default :
2016-03-24 12:10:20 +01:00
pr_info ( " DDBridge: Detected GT link but found invalid ID %08x. You might have to update (flash) the add-on card first. " ,
2015-08-05 17:22:42 +02:00
id ) ;
return - 1 ;
}
2015-09-06 19:08:57 +02:00
link - > ids . devid = id ;
2016-03-24 12:10:20 +01:00
2016-05-06 00:55:41 +02:00
ddbwritel ( dev , 1 , regs + 0x20 ) ;
2015-08-05 17:22:42 +02:00
2016-05-02 16:27:32 +02:00
dev - > handler_data [ 0 ] [ base + l ] = ( unsigned long ) link ;
dev - > handler [ 0 ] [ base + l ] = gtl_irq_handler ;
2016-03-24 12:10:20 +01:00
2016-08-29 18:44:53 +02:00
dev - > link [ l ] . ids . hwid = ddbreadl ( dev , DDB_LINK_TAG ( l ) | 0 ) ;
dev - > link [ l ] . ids . regmapid = ddbreadl ( dev , DDB_LINK_TAG ( l ) | 4 ) ;
2016-10-10 00:19:16 +02:00
dev - > link [ l ] . ids . vendor = id & 0xffff ;
dev - > link [ l ] . ids . device = id > > 16 ;
dev - > link [ l ] . ids . subvendor = subid & 0xffff ;
dev - > link [ l ] . ids . subdevice = subid > > 16 ;
2016-08-29 18:44:53 +02:00
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: GTL %s \n " , dev - > link [ l ] . info - > name ) ;
2016-08-29 18:44:53 +02:00
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: GTL HW %08x REGMAP %08x \n " ,
2016-08-29 18:44:53 +02:00
dev - > link [ l ] . ids . hwid ,
dev - > link [ l ] . ids . regmapid ) ;
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: GTL ID %08x \n " ,
2015-08-05 17:22:42 +02:00
ddbreadl ( dev , DDB_LINK_TAG ( l ) | 8 ) ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
tasklet_init ( & link - > tasklet , link_tasklet , ( unsigned long ) link ) ;
ddbwritel ( dev , 0xffffffff , DDB_LINK_TAG ( l ) | INTERRUPT_ACK ) ;
2016-08-29 18:44:53 +02:00
ddbwritel ( dev , 0x0100000f , DDB_LINK_TAG ( l ) | INTERRUPT_ENABLE ) ;
2015-08-05 17:22:42 +02:00
return 0 ;
}
static int ddb_gtl_init ( struct ddb * dev )
{
2016-05-02 16:27:32 +02:00
u32 l , base = dev - > link [ 0 ] . info - > regmap - > irq_base_gtl ;
2015-08-05 17:22:42 +02:00
2016-05-02 16:27:32 +02:00
dev - > handler_data [ 0 ] [ base ] = ( unsigned long ) dev ;
2017-04-16 21:20:52 +02:00
dev - > handler [ 0 ] [ base ] = gtl_link_handler ;
2016-03-24 12:10:20 +01:00
for ( l = 1 ; l < dev - > link [ 0 ] . info - > regmap - > gtl - > num + 1 ; l + + )
2015-08-05 17:22:42 +02:00
ddb_gtl_init_link ( dev , l ) ;
return 0 ;
}
2016-08-29 18:44:53 +02:00
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static void tempmon_setfan ( struct ddb_link * link )
{
u32 temp , temp2 , pwm ;
2017-04-16 21:20:52 +02:00
if ( ( ddblreadl ( link , TEMPMON_CONTROL ) &
TEMPMON_CONTROL_OVERTEMP ) ! = 0 ) {
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: Over temperature condition \n " ) ;
2016-08-29 18:44:53 +02:00
link - > OverTemperatureError = 1 ;
}
temp = ( ddblreadl ( link , TEMPMON_SENSOR0 ) > > 8 ) & 0xFF ;
if ( temp & 0x80 )
temp = 0 ;
temp2 = ( ddblreadl ( link , TEMPMON_SENSOR1 ) > > 8 ) & 0xFF ;
if ( temp2 & 0x80 )
temp2 = 0 ;
if ( temp2 > temp )
temp = temp2 ;
2017-04-16 21:20:52 +02:00
2016-08-29 18:44:53 +02:00
pwm = ( ddblreadl ( link , TEMPMON_FANCONTROL ) > > 8 ) & 0x0F ;
if ( pwm > 10 )
2017-04-16 21:20:52 +02:00
pwm = 10 ;
2016-08-29 18:44:53 +02:00
if ( temp > = link - > temp_tab [ pwm ] ) {
2017-04-16 21:20:52 +02:00
while ( pwm < 10 & & temp > = link - > temp_tab [ pwm + 1 ] )
2016-08-29 18:44:53 +02:00
pwm + = 1 ;
} else {
2017-04-16 21:20:52 +02:00
while ( pwm > 1 & & temp < link - > temp_tab [ pwm - 2 ] )
2016-08-29 18:44:53 +02:00
pwm - = 1 ;
}
ddblwritel ( link , ( pwm < < 8 ) , TEMPMON_FANCONTROL ) ;
2017-01-19 16:37:50 +01:00
}
2016-08-29 18:44:53 +02:00
static void temp_handler ( unsigned long data )
{
struct ddb_link * link = ( struct ddb_link * ) data ;
2017-04-16 21:20:52 +02:00
2016-08-29 18:44:53 +02:00
spin_lock ( & link - > temp_lock ) ;
tempmon_setfan ( link ) ;
spin_unlock ( & link - > temp_lock ) ;
}
static int tempmon_init ( struct ddb_link * link , int FirstTime )
{
struct ddb * dev = link - > dev ;
int status = 0 ;
u32 l = link - > nr ;
2017-04-16 21:20:52 +02:00
2016-08-29 18:44:53 +02:00
spin_lock_irq ( & link - > temp_lock ) ;
if ( FirstTime ) {
2017-04-16 21:20:52 +02:00
static u8 TemperatureTable [ 11 ] = {
30 , 35 , 40 , 45 , 50 , 55 , 60 , 65 , 70 , 75 , 80 } ;
memcpy ( link - > temp_tab , TemperatureTable ,
sizeof ( TemperatureTable ) ) ;
2016-08-29 18:44:53 +02:00
}
dev - > handler [ l ] [ link - > info - > tempmon_irq ] = temp_handler ;
dev - > handler_data [ l ] [ link - > info - > tempmon_irq ] = ( unsigned long ) link ;
ddblwritel ( link , ( TEMPMON_CONTROL_OVERTEMP | TEMPMON_CONTROL_AUTOSCAN |
TEMPMON_CONTROL_INTENABLE ) ,
TEMPMON_CONTROL ) ;
ddblwritel ( link , ( 3 < < 8 ) , TEMPMON_FANCONTROL ) ;
2017-04-16 21:20:52 +02:00
2016-08-29 18:44:53 +02:00
link - > OverTemperatureError =
2017-04-16 21:20:52 +02:00
( ( ddblreadl ( link , TEMPMON_CONTROL ) &
TEMPMON_CONTROL_OVERTEMP ) ! = 0 ) ;
2016-08-29 18:44:53 +02:00
if ( link - > OverTemperatureError ) {
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: Over temperature condition \n " ) ;
2016-08-29 18:44:53 +02:00
status = - 1 ;
}
tempmon_setfan ( link ) ;
spin_unlock_irq ( & link - > temp_lock ) ;
return status ;
}
static int ddb_init_tempmon ( struct ddb_link * link )
{
struct ddb_info * info = link - > info ;
2017-04-16 21:20:52 +02:00
2016-08-29 18:44:53 +02:00
if ( ! info - > tempmon_irq )
2017-02-09 10:12:43 +01:00
return 0 ;
2016-08-29 18:44:53 +02:00
if ( info - > type = = DDB_OCTOPUS_MAX | |
info - > type = = DDB_OCTOPUS_MAX_CT )
if ( link - > ids . regmapid < 0x00010002 )
2017-02-09 10:12:43 +01:00
return 0 ;
2016-08-29 18:44:53 +02:00
spin_lock_init ( & link - > temp_lock ) ;
2017-02-09 10:12:43 +01:00
return tempmon_init ( link , 1 ) ;
2016-08-29 18:44:53 +02:00
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
2015-08-05 17:22:42 +02:00
static int ddb_init_boards ( struct ddb * dev )
{
struct ddb_info * info ;
2016-08-29 18:44:53 +02:00
struct ddb_link * link ;
2015-08-05 17:22:42 +02:00
u32 l ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
for ( l = 0 ; l < DDB_MAX_LINK ; l + + ) {
2016-08-29 18:44:53 +02:00
link = & dev - > link [ l ] ;
info = link - > info ;
2015-08-05 17:22:42 +02:00
if ( ! info )
continue ;
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: link %u vendor %04x device %04x subvendor %04x subdevice %04x \n " ,
l ,
dev - > link [ l ] . ids . vendor , dev - > link [ l ] . ids . device ,
dev - > link [ l ] . ids . subvendor , dev - > link [ l ] . ids . subdevice ) ;
2017-04-16 21:20:52 +02:00
2015-08-05 17:22:42 +02:00
if ( info - > board_control ) {
ddbwritel ( dev , 0 , DDB_LINK_TAG ( l ) | BOARD_CONTROL ) ;
msleep ( 100 ) ;
2016-03-24 12:10:20 +01:00
ddbwritel ( dev , info - > board_control_2 ,
DDB_LINK_TAG ( l ) | BOARD_CONTROL ) ;
2015-08-05 17:22:42 +02:00
usleep_range ( 2000 , 3000 ) ;
2016-03-24 12:10:20 +01:00
ddbwritel ( dev , info - > board_control_2 |
info - > board_control ,
2015-08-05 17:22:42 +02:00
DDB_LINK_TAG ( l ) | BOARD_CONTROL ) ;
usleep_range ( 2000 , 3000 ) ;
}
2016-08-29 18:44:53 +02:00
ddb_init_tempmon ( link ) ;
2015-08-05 17:22:42 +02:00
}
return 0 ;
}
2017-07-10 18:02:59 +02:00
int ddb_init ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
2016-04-15 22:45:55 +02:00
mutex_init ( & dev - > link [ 0 ] . flash_mutex ) ;
if ( no_init ) {
ddb_device_create ( dev ) ;
2017-04-16 21:20:52 +02:00
return 0 ;
2016-04-15 22:45:55 +02:00
}
2015-08-05 17:22:42 +02:00
if ( dev - > link [ 0 ] . info - > ns_num ) {
ddbwritel ( dev , 1 , ETHER_CONTROL ) ;
dev - > vlan = vlan ;
ddbwritel ( dev , 14 + ( dev - > vlan ? 4 : 0 ) , ETHER_LENGTH ) ;
}
mutex_init ( & dev - > link [ 0 ] . lnb . lock ) ;
2017-04-16 21:20:52 +02:00
2015-08-05 17:22:42 +02:00
if ( dev - > link [ 0 ] . info - > regmap - > gtl )
ddb_gtl_init ( dev ) ;
ddb_init_boards ( dev ) ;
if ( ddb_i2c_init ( dev ) < 0 )
goto fail ;
ddb_ports_init ( dev ) ;
if ( ddb_buffers_alloc ( dev ) < 0 ) {
2016-10-10 00:19:16 +02:00
pr_info ( " DDBridge: Could not allocate buffer memory \n " ) ;
2015-08-05 17:22:42 +02:00
goto fail2 ;
}
if ( ddb_ports_attach ( dev ) < 0 )
goto fail3 ;
ddb_nsd_attach ( dev ) ;
ddb_device_create ( dev ) ;
if ( dev - > link [ 0 ] . info - > fan_num ) {
ddbwritel ( dev , 1 , GPIO_DIRECTION ) ;
ddbwritel ( dev , 1 , GPIO_OUTPUT ) ;
}
if ( dev - > link [ 0 ] . info - > type = = DDB_MOD )
ddbridge_mod_init ( dev ) ;
return 0 ;
fail3 :
ddb_ports_detach ( dev ) ;
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: fail3 \n " ) ;
2015-08-05 17:22:42 +02:00
ddb_ports_release ( dev ) ;
fail2 :
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: fail2 \n " ) ;
2015-08-05 17:22:42 +02:00
ddb_buffers_free ( dev ) ;
ddb_i2c_release ( dev ) ;
fail :
2016-10-10 00:19:16 +02:00
pr_err ( " DDBridge: fail1 \n " ) ;
2015-08-05 17:22:42 +02:00
return - 1 ;
}
2016-05-02 16:27:32 +02:00
static void ddb_reset_io ( struct ddb * dev , u32 reg )
{
ddbwritel ( dev , 0x00 , reg ) ;
ddbwritel ( dev , 0x02 , reg ) ;
ddbwritel ( dev , 0x00 , reg ) ;
}
2017-07-10 18:02:59 +02:00
void ddb_reset_ios ( struct ddb * dev )
2016-05-02 16:27:32 +02:00
{
u32 i ;
struct ddb_regmap * rm = dev - > link [ 0 ] . info - > regmap ;
2017-04-16 21:20:52 +02:00
2016-05-02 16:27:32 +02:00
if ( rm - > input )
for ( i = 0 ; i < rm - > input - > num ; i + + )
2017-04-16 21:20:52 +02:00
ddb_reset_io ( dev ,
rm - > input - > base + i * rm - > input - > size ) ;
2016-05-02 16:27:32 +02:00
if ( rm - > output )
for ( i = 0 ; i < rm - > output - > num ; i + + )
2017-04-16 21:20:52 +02:00
ddb_reset_io ( dev ,
rm - > output - > base + i * rm - > output - > size ) ;
2016-05-02 16:27:32 +02:00
usleep_range ( 5000 , 6000 ) ;
}