162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SMI PCIe driver for DVBSky cards. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2014 Max nibble <nibble.max@gmail.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "smipcie.h" 962306a36Sopenharmony_ci#include "m88ds3103.h" 1062306a36Sopenharmony_ci#include "ts2020.h" 1162306a36Sopenharmony_ci#include "m88rs6000t.h" 1262306a36Sopenharmony_ci#include "si2168.h" 1362306a36Sopenharmony_ci#include "si2157.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic int smi_hw_init(struct smi_dev *dev) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci u32 port_mux, port_ctrl, int_stat; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci /* set port mux.*/ 2262306a36Sopenharmony_ci port_mux = smi_read(MUX_MODE_CTRL); 2362306a36Sopenharmony_ci port_mux &= ~(rbPaMSMask); 2462306a36Sopenharmony_ci port_mux |= rbPaMSDtvNoGpio; 2562306a36Sopenharmony_ci port_mux &= ~(rbPbMSMask); 2662306a36Sopenharmony_ci port_mux |= rbPbMSDtvNoGpio; 2762306a36Sopenharmony_ci port_mux &= ~(0x0f0000); 2862306a36Sopenharmony_ci port_mux |= 0x50000; 2962306a36Sopenharmony_ci smi_write(MUX_MODE_CTRL, port_mux); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci /* set DTV register.*/ 3262306a36Sopenharmony_ci /* Port A */ 3362306a36Sopenharmony_ci port_ctrl = smi_read(VIDEO_CTRL_STATUS_A); 3462306a36Sopenharmony_ci port_ctrl &= ~0x01; 3562306a36Sopenharmony_ci smi_write(VIDEO_CTRL_STATUS_A, port_ctrl); 3662306a36Sopenharmony_ci port_ctrl = smi_read(MPEG2_CTRL_A); 3762306a36Sopenharmony_ci port_ctrl &= ~0x40; 3862306a36Sopenharmony_ci port_ctrl |= 0x80; 3962306a36Sopenharmony_ci smi_write(MPEG2_CTRL_A, port_ctrl); 4062306a36Sopenharmony_ci /* Port B */ 4162306a36Sopenharmony_ci port_ctrl = smi_read(VIDEO_CTRL_STATUS_B); 4262306a36Sopenharmony_ci port_ctrl &= ~0x01; 4362306a36Sopenharmony_ci smi_write(VIDEO_CTRL_STATUS_B, port_ctrl); 4462306a36Sopenharmony_ci port_ctrl = smi_read(MPEG2_CTRL_B); 4562306a36Sopenharmony_ci port_ctrl &= ~0x40; 4662306a36Sopenharmony_ci port_ctrl |= 0x80; 4762306a36Sopenharmony_ci smi_write(MPEG2_CTRL_B, port_ctrl); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* disable and clear interrupt.*/ 5062306a36Sopenharmony_ci smi_write(MSI_INT_ENA_CLR, ALL_INT); 5162306a36Sopenharmony_ci int_stat = smi_read(MSI_INT_STATUS); 5262306a36Sopenharmony_ci smi_write(MSI_INT_STATUS_CLR, int_stat); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* reset demod.*/ 5562306a36Sopenharmony_ci smi_clear(PERIPHERAL_CTRL, 0x0303); 5662306a36Sopenharmony_ci msleep(50); 5762306a36Sopenharmony_ci smi_set(PERIPHERAL_CTRL, 0x0101); 5862306a36Sopenharmony_ci return 0; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* i2c bit bus.*/ 6262306a36Sopenharmony_cistatic void smi_i2c_cfg(struct smi_dev *dev, u32 sw_ctl) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci u32 dwCtrl; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci dwCtrl = smi_read(sw_ctl); 6762306a36Sopenharmony_ci dwCtrl &= ~0x18; /* disable output.*/ 6862306a36Sopenharmony_ci dwCtrl |= 0x21; /* reset and software mode.*/ 6962306a36Sopenharmony_ci dwCtrl &= ~0xff00; 7062306a36Sopenharmony_ci dwCtrl |= 0x6400; 7162306a36Sopenharmony_ci smi_write(sw_ctl, dwCtrl); 7262306a36Sopenharmony_ci msleep(20); 7362306a36Sopenharmony_ci dwCtrl = smi_read(sw_ctl); 7462306a36Sopenharmony_ci dwCtrl &= ~0x20; 7562306a36Sopenharmony_ci smi_write(sw_ctl, dwCtrl); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic void smi_i2c_setsda(struct smi_dev *dev, int state, u32 sw_ctl) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci if (state) { 8162306a36Sopenharmony_ci /* set as input.*/ 8262306a36Sopenharmony_ci smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN); 8362306a36Sopenharmony_ci } else { 8462306a36Sopenharmony_ci smi_clear(sw_ctl, SW_I2C_MSK_DAT_OUT); 8562306a36Sopenharmony_ci /* set as output.*/ 8662306a36Sopenharmony_ci smi_set(sw_ctl, SW_I2C_MSK_DAT_EN); 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic void smi_i2c_setscl(void *data, int state, u32 sw_ctl) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct smi_dev *dev = data; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (state) { 9562306a36Sopenharmony_ci /* set as input.*/ 9662306a36Sopenharmony_ci smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN); 9762306a36Sopenharmony_ci } else { 9862306a36Sopenharmony_ci smi_clear(sw_ctl, SW_I2C_MSK_CLK_OUT); 9962306a36Sopenharmony_ci /* set as output.*/ 10062306a36Sopenharmony_ci smi_set(sw_ctl, SW_I2C_MSK_CLK_EN); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int smi_i2c_getsda(void *data, u32 sw_ctl) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct smi_dev *dev = data; 10762306a36Sopenharmony_ci /* set as input.*/ 10862306a36Sopenharmony_ci smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN); 10962306a36Sopenharmony_ci udelay(1); 11062306a36Sopenharmony_ci return (smi_read(sw_ctl) & SW_I2C_MSK_DAT_IN) ? 1 : 0; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int smi_i2c_getscl(void *data, u32 sw_ctl) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct smi_dev *dev = data; 11662306a36Sopenharmony_ci /* set as input.*/ 11762306a36Sopenharmony_ci smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN); 11862306a36Sopenharmony_ci udelay(1); 11962306a36Sopenharmony_ci return (smi_read(sw_ctl) & SW_I2C_MSK_CLK_IN) ? 1 : 0; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci/* i2c 0.*/ 12262306a36Sopenharmony_cistatic void smi_i2c0_setsda(void *data, int state) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct smi_dev *dev = data; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci smi_i2c_setsda(dev, state, I2C_A_SW_CTL); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void smi_i2c0_setscl(void *data, int state) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct smi_dev *dev = data; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci smi_i2c_setscl(dev, state, I2C_A_SW_CTL); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int smi_i2c0_getsda(void *data) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct smi_dev *dev = data; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return smi_i2c_getsda(dev, I2C_A_SW_CTL); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic int smi_i2c0_getscl(void *data) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct smi_dev *dev = data; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return smi_i2c_getscl(dev, I2C_A_SW_CTL); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci/* i2c 1.*/ 15062306a36Sopenharmony_cistatic void smi_i2c1_setsda(void *data, int state) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct smi_dev *dev = data; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci smi_i2c_setsda(dev, state, I2C_B_SW_CTL); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic void smi_i2c1_setscl(void *data, int state) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct smi_dev *dev = data; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci smi_i2c_setscl(dev, state, I2C_B_SW_CTL); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int smi_i2c1_getsda(void *data) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct smi_dev *dev = data; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return smi_i2c_getsda(dev, I2C_B_SW_CTL); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int smi_i2c1_getscl(void *data) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct smi_dev *dev = data; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci return smi_i2c_getscl(dev, I2C_B_SW_CTL); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic int smi_i2c_init(struct smi_dev *dev) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci int ret; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* i2c bus 0 */ 18362306a36Sopenharmony_ci smi_i2c_cfg(dev, I2C_A_SW_CTL); 18462306a36Sopenharmony_ci i2c_set_adapdata(&dev->i2c_bus[0], dev); 18562306a36Sopenharmony_ci strscpy(dev->i2c_bus[0].name, "SMI-I2C0", sizeof(dev->i2c_bus[0].name)); 18662306a36Sopenharmony_ci dev->i2c_bus[0].owner = THIS_MODULE; 18762306a36Sopenharmony_ci dev->i2c_bus[0].dev.parent = &dev->pci_dev->dev; 18862306a36Sopenharmony_ci dev->i2c_bus[0].algo_data = &dev->i2c_bit[0]; 18962306a36Sopenharmony_ci dev->i2c_bit[0].data = dev; 19062306a36Sopenharmony_ci dev->i2c_bit[0].setsda = smi_i2c0_setsda; 19162306a36Sopenharmony_ci dev->i2c_bit[0].setscl = smi_i2c0_setscl; 19262306a36Sopenharmony_ci dev->i2c_bit[0].getsda = smi_i2c0_getsda; 19362306a36Sopenharmony_ci dev->i2c_bit[0].getscl = smi_i2c0_getscl; 19462306a36Sopenharmony_ci dev->i2c_bit[0].udelay = 12; 19562306a36Sopenharmony_ci dev->i2c_bit[0].timeout = 10; 19662306a36Sopenharmony_ci /* Raise SCL and SDA */ 19762306a36Sopenharmony_ci smi_i2c0_setsda(dev, 1); 19862306a36Sopenharmony_ci smi_i2c0_setscl(dev, 1); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci ret = i2c_bit_add_bus(&dev->i2c_bus[0]); 20162306a36Sopenharmony_ci if (ret < 0) 20262306a36Sopenharmony_ci return ret; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* i2c bus 1 */ 20562306a36Sopenharmony_ci smi_i2c_cfg(dev, I2C_B_SW_CTL); 20662306a36Sopenharmony_ci i2c_set_adapdata(&dev->i2c_bus[1], dev); 20762306a36Sopenharmony_ci strscpy(dev->i2c_bus[1].name, "SMI-I2C1", sizeof(dev->i2c_bus[1].name)); 20862306a36Sopenharmony_ci dev->i2c_bus[1].owner = THIS_MODULE; 20962306a36Sopenharmony_ci dev->i2c_bus[1].dev.parent = &dev->pci_dev->dev; 21062306a36Sopenharmony_ci dev->i2c_bus[1].algo_data = &dev->i2c_bit[1]; 21162306a36Sopenharmony_ci dev->i2c_bit[1].data = dev; 21262306a36Sopenharmony_ci dev->i2c_bit[1].setsda = smi_i2c1_setsda; 21362306a36Sopenharmony_ci dev->i2c_bit[1].setscl = smi_i2c1_setscl; 21462306a36Sopenharmony_ci dev->i2c_bit[1].getsda = smi_i2c1_getsda; 21562306a36Sopenharmony_ci dev->i2c_bit[1].getscl = smi_i2c1_getscl; 21662306a36Sopenharmony_ci dev->i2c_bit[1].udelay = 12; 21762306a36Sopenharmony_ci dev->i2c_bit[1].timeout = 10; 21862306a36Sopenharmony_ci /* Raise SCL and SDA */ 21962306a36Sopenharmony_ci smi_i2c1_setsda(dev, 1); 22062306a36Sopenharmony_ci smi_i2c1_setscl(dev, 1); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci ret = i2c_bit_add_bus(&dev->i2c_bus[1]); 22362306a36Sopenharmony_ci if (ret < 0) 22462306a36Sopenharmony_ci i2c_del_adapter(&dev->i2c_bus[0]); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci return ret; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic void smi_i2c_exit(struct smi_dev *dev) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci i2c_del_adapter(&dev->i2c_bus[0]); 23262306a36Sopenharmony_ci i2c_del_adapter(&dev->i2c_bus[1]); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int smi_read_eeprom(struct i2c_adapter *i2c, u16 reg, u8 *data, u16 size) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci int ret; 23862306a36Sopenharmony_ci u8 b0[2] = { (reg >> 8) & 0xff, reg & 0xff }; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci struct i2c_msg msg[] = { 24162306a36Sopenharmony_ci { .addr = 0x50, .flags = 0, 24262306a36Sopenharmony_ci .buf = b0, .len = 2 }, 24362306a36Sopenharmony_ci { .addr = 0x50, .flags = I2C_M_RD, 24462306a36Sopenharmony_ci .buf = data, .len = size } 24562306a36Sopenharmony_ci }; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci ret = i2c_transfer(i2c, msg, 2); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (ret != 2) { 25062306a36Sopenharmony_ci dev_err(&i2c->dev, "%s: reg=0x%x (error=%d)\n", 25162306a36Sopenharmony_ci __func__, reg, ret); 25262306a36Sopenharmony_ci return ret; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci return ret; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/* ts port interrupt operations */ 25862306a36Sopenharmony_cistatic void smi_port_disableInterrupt(struct smi_port *port) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct smi_dev *dev = port->dev; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci smi_write(MSI_INT_ENA_CLR, 26362306a36Sopenharmony_ci (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic void smi_port_enableInterrupt(struct smi_port *port) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct smi_dev *dev = port->dev; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci smi_write(MSI_INT_ENA_SET, 27162306a36Sopenharmony_ci (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic void smi_port_clearInterrupt(struct smi_port *port) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct smi_dev *dev = port->dev; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci smi_write(MSI_INT_STATUS_CLR, 27962306a36Sopenharmony_ci (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/* tasklet handler: DMA data to dmx.*/ 28362306a36Sopenharmony_cistatic void smi_dma_xfer(struct tasklet_struct *t) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct smi_port *port = from_tasklet(port, t, tasklet); 28662306a36Sopenharmony_ci struct smi_dev *dev = port->dev; 28762306a36Sopenharmony_ci u32 intr_status, finishedData, dmaManagement; 28862306a36Sopenharmony_ci u8 dmaChan0State, dmaChan1State; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci intr_status = port->_int_status; 29162306a36Sopenharmony_ci dmaManagement = smi_read(port->DMA_MANAGEMENT); 29262306a36Sopenharmony_ci dmaChan0State = (u8)((dmaManagement & 0x00000030) >> 4); 29362306a36Sopenharmony_ci dmaChan1State = (u8)((dmaManagement & 0x00300000) >> 20); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* CH-0 DMA interrupt.*/ 29662306a36Sopenharmony_ci if ((intr_status & port->_dmaInterruptCH0) && (dmaChan0State == 0x01)) { 29762306a36Sopenharmony_ci dev_dbg(&dev->pci_dev->dev, 29862306a36Sopenharmony_ci "Port[%d]-DMA CH0 engine complete successful !\n", 29962306a36Sopenharmony_ci port->idx); 30062306a36Sopenharmony_ci finishedData = smi_read(port->DMA_CHAN0_TRANS_STATE); 30162306a36Sopenharmony_ci finishedData &= 0x003FFFFF; 30262306a36Sopenharmony_ci /* value of DMA_PORT0_CHAN0_TRANS_STATE register [21:0] 30362306a36Sopenharmony_ci * indicate dma total transfer length and 30462306a36Sopenharmony_ci * zero of [21:0] indicate dma total transfer length 30562306a36Sopenharmony_ci * equal to 0x400000 (4MB)*/ 30662306a36Sopenharmony_ci if (finishedData == 0) 30762306a36Sopenharmony_ci finishedData = 0x00400000; 30862306a36Sopenharmony_ci if (finishedData != SMI_TS_DMA_BUF_SIZE) { 30962306a36Sopenharmony_ci dev_dbg(&dev->pci_dev->dev, 31062306a36Sopenharmony_ci "DMA CH0 engine complete length mismatched, finish data=%d !\n", 31162306a36Sopenharmony_ci finishedData); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci dvb_dmx_swfilter_packets(&port->demux, 31462306a36Sopenharmony_ci port->cpu_addr[0], (finishedData / 188)); 31562306a36Sopenharmony_ci /*dvb_dmx_swfilter(&port->demux, 31662306a36Sopenharmony_ci port->cpu_addr[0], finishedData);*/ 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci /* CH-1 DMA interrupt.*/ 31962306a36Sopenharmony_ci if ((intr_status & port->_dmaInterruptCH1) && (dmaChan1State == 0x01)) { 32062306a36Sopenharmony_ci dev_dbg(&dev->pci_dev->dev, 32162306a36Sopenharmony_ci "Port[%d]-DMA CH1 engine complete successful !\n", 32262306a36Sopenharmony_ci port->idx); 32362306a36Sopenharmony_ci finishedData = smi_read(port->DMA_CHAN1_TRANS_STATE); 32462306a36Sopenharmony_ci finishedData &= 0x003FFFFF; 32562306a36Sopenharmony_ci /* value of DMA_PORT0_CHAN0_TRANS_STATE register [21:0] 32662306a36Sopenharmony_ci * indicate dma total transfer length and 32762306a36Sopenharmony_ci * zero of [21:0] indicate dma total transfer length 32862306a36Sopenharmony_ci * equal to 0x400000 (4MB)*/ 32962306a36Sopenharmony_ci if (finishedData == 0) 33062306a36Sopenharmony_ci finishedData = 0x00400000; 33162306a36Sopenharmony_ci if (finishedData != SMI_TS_DMA_BUF_SIZE) { 33262306a36Sopenharmony_ci dev_dbg(&dev->pci_dev->dev, 33362306a36Sopenharmony_ci "DMA CH1 engine complete length mismatched, finish data=%d !\n", 33462306a36Sopenharmony_ci finishedData); 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci dvb_dmx_swfilter_packets(&port->demux, 33762306a36Sopenharmony_ci port->cpu_addr[1], (finishedData / 188)); 33862306a36Sopenharmony_ci /*dvb_dmx_swfilter(&port->demux, 33962306a36Sopenharmony_ci port->cpu_addr[1], finishedData);*/ 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci /* restart DMA.*/ 34262306a36Sopenharmony_ci if (intr_status & port->_dmaInterruptCH0) 34362306a36Sopenharmony_ci dmaManagement |= 0x00000002; 34462306a36Sopenharmony_ci if (intr_status & port->_dmaInterruptCH1) 34562306a36Sopenharmony_ci dmaManagement |= 0x00020000; 34662306a36Sopenharmony_ci smi_write(port->DMA_MANAGEMENT, dmaManagement); 34762306a36Sopenharmony_ci /* Re-enable interrupts */ 34862306a36Sopenharmony_ci smi_port_enableInterrupt(port); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void smi_port_dma_free(struct smi_port *port) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci if (port->cpu_addr[0]) { 35462306a36Sopenharmony_ci dma_free_coherent(&port->dev->pci_dev->dev, 35562306a36Sopenharmony_ci SMI_TS_DMA_BUF_SIZE, port->cpu_addr[0], 35662306a36Sopenharmony_ci port->dma_addr[0]); 35762306a36Sopenharmony_ci port->cpu_addr[0] = NULL; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci if (port->cpu_addr[1]) { 36062306a36Sopenharmony_ci dma_free_coherent(&port->dev->pci_dev->dev, 36162306a36Sopenharmony_ci SMI_TS_DMA_BUF_SIZE, port->cpu_addr[1], 36262306a36Sopenharmony_ci port->dma_addr[1]); 36362306a36Sopenharmony_ci port->cpu_addr[1] = NULL; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic int smi_port_init(struct smi_port *port, int dmaChanUsed) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci dev_dbg(&port->dev->pci_dev->dev, 37062306a36Sopenharmony_ci "%s, port %d, dmaused %d\n", __func__, port->idx, dmaChanUsed); 37162306a36Sopenharmony_ci port->enable = 0; 37262306a36Sopenharmony_ci if (port->idx == 0) { 37362306a36Sopenharmony_ci /* Port A */ 37462306a36Sopenharmony_ci port->_dmaInterruptCH0 = dmaChanUsed & 0x01; 37562306a36Sopenharmony_ci port->_dmaInterruptCH1 = dmaChanUsed & 0x02; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci port->DMA_CHAN0_ADDR_LOW = DMA_PORTA_CHAN0_ADDR_LOW; 37862306a36Sopenharmony_ci port->DMA_CHAN0_ADDR_HI = DMA_PORTA_CHAN0_ADDR_HI; 37962306a36Sopenharmony_ci port->DMA_CHAN0_TRANS_STATE = DMA_PORTA_CHAN0_TRANS_STATE; 38062306a36Sopenharmony_ci port->DMA_CHAN0_CONTROL = DMA_PORTA_CHAN0_CONTROL; 38162306a36Sopenharmony_ci port->DMA_CHAN1_ADDR_LOW = DMA_PORTA_CHAN1_ADDR_LOW; 38262306a36Sopenharmony_ci port->DMA_CHAN1_ADDR_HI = DMA_PORTA_CHAN1_ADDR_HI; 38362306a36Sopenharmony_ci port->DMA_CHAN1_TRANS_STATE = DMA_PORTA_CHAN1_TRANS_STATE; 38462306a36Sopenharmony_ci port->DMA_CHAN1_CONTROL = DMA_PORTA_CHAN1_CONTROL; 38562306a36Sopenharmony_ci port->DMA_MANAGEMENT = DMA_PORTA_MANAGEMENT; 38662306a36Sopenharmony_ci } else { 38762306a36Sopenharmony_ci /* Port B */ 38862306a36Sopenharmony_ci port->_dmaInterruptCH0 = (dmaChanUsed << 2) & 0x04; 38962306a36Sopenharmony_ci port->_dmaInterruptCH1 = (dmaChanUsed << 2) & 0x08; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci port->DMA_CHAN0_ADDR_LOW = DMA_PORTB_CHAN0_ADDR_LOW; 39262306a36Sopenharmony_ci port->DMA_CHAN0_ADDR_HI = DMA_PORTB_CHAN0_ADDR_HI; 39362306a36Sopenharmony_ci port->DMA_CHAN0_TRANS_STATE = DMA_PORTB_CHAN0_TRANS_STATE; 39462306a36Sopenharmony_ci port->DMA_CHAN0_CONTROL = DMA_PORTB_CHAN0_CONTROL; 39562306a36Sopenharmony_ci port->DMA_CHAN1_ADDR_LOW = DMA_PORTB_CHAN1_ADDR_LOW; 39662306a36Sopenharmony_ci port->DMA_CHAN1_ADDR_HI = DMA_PORTB_CHAN1_ADDR_HI; 39762306a36Sopenharmony_ci port->DMA_CHAN1_TRANS_STATE = DMA_PORTB_CHAN1_TRANS_STATE; 39862306a36Sopenharmony_ci port->DMA_CHAN1_CONTROL = DMA_PORTB_CHAN1_CONTROL; 39962306a36Sopenharmony_ci port->DMA_MANAGEMENT = DMA_PORTB_MANAGEMENT; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (port->_dmaInterruptCH0) { 40362306a36Sopenharmony_ci port->cpu_addr[0] = dma_alloc_coherent(&port->dev->pci_dev->dev, 40462306a36Sopenharmony_ci SMI_TS_DMA_BUF_SIZE, 40562306a36Sopenharmony_ci &port->dma_addr[0], 40662306a36Sopenharmony_ci GFP_KERNEL); 40762306a36Sopenharmony_ci if (!port->cpu_addr[0]) { 40862306a36Sopenharmony_ci dev_err(&port->dev->pci_dev->dev, 40962306a36Sopenharmony_ci "Port[%d] DMA CH0 memory allocation failed!\n", 41062306a36Sopenharmony_ci port->idx); 41162306a36Sopenharmony_ci goto err; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (port->_dmaInterruptCH1) { 41662306a36Sopenharmony_ci port->cpu_addr[1] = dma_alloc_coherent(&port->dev->pci_dev->dev, 41762306a36Sopenharmony_ci SMI_TS_DMA_BUF_SIZE, 41862306a36Sopenharmony_ci &port->dma_addr[1], 41962306a36Sopenharmony_ci GFP_KERNEL); 42062306a36Sopenharmony_ci if (!port->cpu_addr[1]) { 42162306a36Sopenharmony_ci dev_err(&port->dev->pci_dev->dev, 42262306a36Sopenharmony_ci "Port[%d] DMA CH1 memory allocation failed!\n", 42362306a36Sopenharmony_ci port->idx); 42462306a36Sopenharmony_ci goto err; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci smi_port_disableInterrupt(port); 42962306a36Sopenharmony_ci tasklet_setup(&port->tasklet, smi_dma_xfer); 43062306a36Sopenharmony_ci tasklet_disable(&port->tasklet); 43162306a36Sopenharmony_ci port->enable = 1; 43262306a36Sopenharmony_ci return 0; 43362306a36Sopenharmony_cierr: 43462306a36Sopenharmony_ci smi_port_dma_free(port); 43562306a36Sopenharmony_ci return -ENOMEM; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic void smi_port_exit(struct smi_port *port) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci smi_port_disableInterrupt(port); 44162306a36Sopenharmony_ci tasklet_kill(&port->tasklet); 44262306a36Sopenharmony_ci smi_port_dma_free(port); 44362306a36Sopenharmony_ci port->enable = 0; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic int smi_port_irq(struct smi_port *port, u32 int_status) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci u32 port_req_irq = port->_dmaInterruptCH0 | port->_dmaInterruptCH1; 44962306a36Sopenharmony_ci int handled = 0; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (int_status & port_req_irq) { 45262306a36Sopenharmony_ci smi_port_disableInterrupt(port); 45362306a36Sopenharmony_ci port->_int_status = int_status; 45462306a36Sopenharmony_ci smi_port_clearInterrupt(port); 45562306a36Sopenharmony_ci tasklet_schedule(&port->tasklet); 45662306a36Sopenharmony_ci handled = 1; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci return handled; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic irqreturn_t smi_irq_handler(int irq, void *dev_id) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct smi_dev *dev = dev_id; 46462306a36Sopenharmony_ci struct smi_port *port0 = &dev->ts_port[0]; 46562306a36Sopenharmony_ci struct smi_port *port1 = &dev->ts_port[1]; 46662306a36Sopenharmony_ci struct smi_rc *ir = &dev->ir; 46762306a36Sopenharmony_ci int handled = 0; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci u32 intr_status = smi_read(MSI_INT_STATUS); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* ts0 interrupt.*/ 47262306a36Sopenharmony_ci if (dev->info->ts_0) 47362306a36Sopenharmony_ci handled += smi_port_irq(port0, intr_status); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* ts1 interrupt.*/ 47662306a36Sopenharmony_ci if (dev->info->ts_1) 47762306a36Sopenharmony_ci handled += smi_port_irq(port1, intr_status); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* ir interrupt.*/ 48062306a36Sopenharmony_ci handled += smi_ir_irq(ir, intr_status); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return IRQ_RETVAL(handled); 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic struct i2c_client *smi_add_i2c_client(struct i2c_adapter *adapter, 48662306a36Sopenharmony_ci struct i2c_board_info *info) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct i2c_client *client; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci request_module(info->type); 49162306a36Sopenharmony_ci client = i2c_new_client_device(adapter, info); 49262306a36Sopenharmony_ci if (!i2c_client_has_driver(client)) 49362306a36Sopenharmony_ci goto err_add_i2c_client; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (!try_module_get(client->dev.driver->owner)) { 49662306a36Sopenharmony_ci i2c_unregister_device(client); 49762306a36Sopenharmony_ci goto err_add_i2c_client; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci return client; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cierr_add_i2c_client: 50262306a36Sopenharmony_ci client = NULL; 50362306a36Sopenharmony_ci return client; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic void smi_del_i2c_client(struct i2c_client *client) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci module_put(client->dev.driver->owner); 50962306a36Sopenharmony_ci i2c_unregister_device(client); 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic const struct m88ds3103_config smi_dvbsky_m88ds3103_cfg = { 51362306a36Sopenharmony_ci .i2c_addr = 0x68, 51462306a36Sopenharmony_ci .clock = 27000000, 51562306a36Sopenharmony_ci .i2c_wr_max = 33, 51662306a36Sopenharmony_ci .clock_out = 0, 51762306a36Sopenharmony_ci .ts_mode = M88DS3103_TS_PARALLEL, 51862306a36Sopenharmony_ci .ts_clk = 16000, 51962306a36Sopenharmony_ci .ts_clk_pol = 1, 52062306a36Sopenharmony_ci .agc = 0x99, 52162306a36Sopenharmony_ci .lnb_hv_pol = 0, 52262306a36Sopenharmony_ci .lnb_en_pol = 1, 52362306a36Sopenharmony_ci}; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic int smi_dvbsky_m88ds3103_fe_attach(struct smi_port *port) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci int ret = 0; 52862306a36Sopenharmony_ci struct smi_dev *dev = port->dev; 52962306a36Sopenharmony_ci struct i2c_adapter *i2c; 53062306a36Sopenharmony_ci /* tuner I2C module */ 53162306a36Sopenharmony_ci struct i2c_adapter *tuner_i2c_adapter; 53262306a36Sopenharmony_ci struct i2c_client *tuner_client; 53362306a36Sopenharmony_ci struct i2c_board_info tuner_info; 53462306a36Sopenharmony_ci struct ts2020_config ts2020_config = {}; 53562306a36Sopenharmony_ci memset(&tuner_info, 0, sizeof(struct i2c_board_info)); 53662306a36Sopenharmony_ci i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* attach demod */ 53962306a36Sopenharmony_ci port->fe = dvb_attach(m88ds3103_attach, 54062306a36Sopenharmony_ci &smi_dvbsky_m88ds3103_cfg, i2c, &tuner_i2c_adapter); 54162306a36Sopenharmony_ci if (!port->fe) { 54262306a36Sopenharmony_ci ret = -ENODEV; 54362306a36Sopenharmony_ci return ret; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci /* attach tuner */ 54662306a36Sopenharmony_ci ts2020_config.fe = port->fe; 54762306a36Sopenharmony_ci strscpy(tuner_info.type, "ts2020", I2C_NAME_SIZE); 54862306a36Sopenharmony_ci tuner_info.addr = 0x60; 54962306a36Sopenharmony_ci tuner_info.platform_data = &ts2020_config; 55062306a36Sopenharmony_ci tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info); 55162306a36Sopenharmony_ci if (!tuner_client) { 55262306a36Sopenharmony_ci ret = -ENODEV; 55362306a36Sopenharmony_ci goto err_tuner_i2c_device; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* delegate signal strength measurement to tuner */ 55762306a36Sopenharmony_ci port->fe->ops.read_signal_strength = 55862306a36Sopenharmony_ci port->fe->ops.tuner_ops.get_rf_strength; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci port->i2c_client_tuner = tuner_client; 56162306a36Sopenharmony_ci return ret; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cierr_tuner_i2c_device: 56462306a36Sopenharmony_ci dvb_frontend_detach(port->fe); 56562306a36Sopenharmony_ci return ret; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic const struct m88ds3103_config smi_dvbsky_m88rs6000_cfg = { 56962306a36Sopenharmony_ci .i2c_addr = 0x69, 57062306a36Sopenharmony_ci .clock = 27000000, 57162306a36Sopenharmony_ci .i2c_wr_max = 33, 57262306a36Sopenharmony_ci .ts_mode = M88DS3103_TS_PARALLEL, 57362306a36Sopenharmony_ci .ts_clk = 16000, 57462306a36Sopenharmony_ci .ts_clk_pol = 1, 57562306a36Sopenharmony_ci .agc = 0x99, 57662306a36Sopenharmony_ci .lnb_hv_pol = 0, 57762306a36Sopenharmony_ci .lnb_en_pol = 1, 57862306a36Sopenharmony_ci}; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic int smi_dvbsky_m88rs6000_fe_attach(struct smi_port *port) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci int ret = 0; 58362306a36Sopenharmony_ci struct smi_dev *dev = port->dev; 58462306a36Sopenharmony_ci struct i2c_adapter *i2c; 58562306a36Sopenharmony_ci /* tuner I2C module */ 58662306a36Sopenharmony_ci struct i2c_adapter *tuner_i2c_adapter; 58762306a36Sopenharmony_ci struct i2c_client *tuner_client; 58862306a36Sopenharmony_ci struct i2c_board_info tuner_info; 58962306a36Sopenharmony_ci struct m88rs6000t_config m88rs6000t_config; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci memset(&tuner_info, 0, sizeof(struct i2c_board_info)); 59262306a36Sopenharmony_ci i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* attach demod */ 59562306a36Sopenharmony_ci port->fe = dvb_attach(m88ds3103_attach, 59662306a36Sopenharmony_ci &smi_dvbsky_m88rs6000_cfg, i2c, &tuner_i2c_adapter); 59762306a36Sopenharmony_ci if (!port->fe) { 59862306a36Sopenharmony_ci ret = -ENODEV; 59962306a36Sopenharmony_ci return ret; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci /* attach tuner */ 60262306a36Sopenharmony_ci m88rs6000t_config.fe = port->fe; 60362306a36Sopenharmony_ci strscpy(tuner_info.type, "m88rs6000t", I2C_NAME_SIZE); 60462306a36Sopenharmony_ci tuner_info.addr = 0x21; 60562306a36Sopenharmony_ci tuner_info.platform_data = &m88rs6000t_config; 60662306a36Sopenharmony_ci tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info); 60762306a36Sopenharmony_ci if (!tuner_client) { 60862306a36Sopenharmony_ci ret = -ENODEV; 60962306a36Sopenharmony_ci goto err_tuner_i2c_device; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* delegate signal strength measurement to tuner */ 61362306a36Sopenharmony_ci port->fe->ops.read_signal_strength = 61462306a36Sopenharmony_ci port->fe->ops.tuner_ops.get_rf_strength; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci port->i2c_client_tuner = tuner_client; 61762306a36Sopenharmony_ci return ret; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cierr_tuner_i2c_device: 62062306a36Sopenharmony_ci dvb_frontend_detach(port->fe); 62162306a36Sopenharmony_ci return ret; 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cistatic int smi_dvbsky_sit2_fe_attach(struct smi_port *port) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci int ret = 0; 62762306a36Sopenharmony_ci struct smi_dev *dev = port->dev; 62862306a36Sopenharmony_ci struct i2c_adapter *i2c; 62962306a36Sopenharmony_ci struct i2c_adapter *tuner_i2c_adapter; 63062306a36Sopenharmony_ci struct i2c_client *client_tuner, *client_demod; 63162306a36Sopenharmony_ci struct i2c_board_info client_info; 63262306a36Sopenharmony_ci struct si2168_config si2168_config; 63362306a36Sopenharmony_ci struct si2157_config si2157_config; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* select i2c bus */ 63662306a36Sopenharmony_ci i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* attach demod */ 63962306a36Sopenharmony_ci memset(&si2168_config, 0, sizeof(si2168_config)); 64062306a36Sopenharmony_ci si2168_config.i2c_adapter = &tuner_i2c_adapter; 64162306a36Sopenharmony_ci si2168_config.fe = &port->fe; 64262306a36Sopenharmony_ci si2168_config.ts_mode = SI2168_TS_PARALLEL; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci memset(&client_info, 0, sizeof(struct i2c_board_info)); 64562306a36Sopenharmony_ci strscpy(client_info.type, "si2168", I2C_NAME_SIZE); 64662306a36Sopenharmony_ci client_info.addr = 0x64; 64762306a36Sopenharmony_ci client_info.platform_data = &si2168_config; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci client_demod = smi_add_i2c_client(i2c, &client_info); 65062306a36Sopenharmony_ci if (!client_demod) { 65162306a36Sopenharmony_ci ret = -ENODEV; 65262306a36Sopenharmony_ci return ret; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci port->i2c_client_demod = client_demod; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* attach tuner */ 65762306a36Sopenharmony_ci memset(&si2157_config, 0, sizeof(si2157_config)); 65862306a36Sopenharmony_ci si2157_config.fe = port->fe; 65962306a36Sopenharmony_ci si2157_config.if_port = 1; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci memset(&client_info, 0, sizeof(struct i2c_board_info)); 66262306a36Sopenharmony_ci strscpy(client_info.type, "si2157", I2C_NAME_SIZE); 66362306a36Sopenharmony_ci client_info.addr = 0x60; 66462306a36Sopenharmony_ci client_info.platform_data = &si2157_config; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci client_tuner = smi_add_i2c_client(tuner_i2c_adapter, &client_info); 66762306a36Sopenharmony_ci if (!client_tuner) { 66862306a36Sopenharmony_ci smi_del_i2c_client(port->i2c_client_demod); 66962306a36Sopenharmony_ci port->i2c_client_demod = NULL; 67062306a36Sopenharmony_ci ret = -ENODEV; 67162306a36Sopenharmony_ci return ret; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci port->i2c_client_tuner = client_tuner; 67462306a36Sopenharmony_ci return ret; 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic int smi_fe_init(struct smi_port *port) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci int ret = 0; 68062306a36Sopenharmony_ci struct smi_dev *dev = port->dev; 68162306a36Sopenharmony_ci struct dvb_adapter *adap = &port->dvb_adapter; 68262306a36Sopenharmony_ci u8 mac_ee[16]; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci dev_dbg(&port->dev->pci_dev->dev, 68562306a36Sopenharmony_ci "%s: port %d, fe_type = %d\n", 68662306a36Sopenharmony_ci __func__, port->idx, port->fe_type); 68762306a36Sopenharmony_ci switch (port->fe_type) { 68862306a36Sopenharmony_ci case DVBSKY_FE_M88DS3103: 68962306a36Sopenharmony_ci ret = smi_dvbsky_m88ds3103_fe_attach(port); 69062306a36Sopenharmony_ci break; 69162306a36Sopenharmony_ci case DVBSKY_FE_M88RS6000: 69262306a36Sopenharmony_ci ret = smi_dvbsky_m88rs6000_fe_attach(port); 69362306a36Sopenharmony_ci break; 69462306a36Sopenharmony_ci case DVBSKY_FE_SIT2: 69562306a36Sopenharmony_ci ret = smi_dvbsky_sit2_fe_attach(port); 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci if (ret < 0) 69962306a36Sopenharmony_ci return ret; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci /* register dvb frontend */ 70262306a36Sopenharmony_ci ret = dvb_register_frontend(adap, port->fe); 70362306a36Sopenharmony_ci if (ret < 0) { 70462306a36Sopenharmony_ci if (port->i2c_client_tuner) 70562306a36Sopenharmony_ci smi_del_i2c_client(port->i2c_client_tuner); 70662306a36Sopenharmony_ci if (port->i2c_client_demod) 70762306a36Sopenharmony_ci smi_del_i2c_client(port->i2c_client_demod); 70862306a36Sopenharmony_ci dvb_frontend_detach(port->fe); 70962306a36Sopenharmony_ci return ret; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci /* init MAC.*/ 71262306a36Sopenharmony_ci ret = smi_read_eeprom(&dev->i2c_bus[0], 0xc0, mac_ee, 16); 71362306a36Sopenharmony_ci dev_info(&port->dev->pci_dev->dev, 71462306a36Sopenharmony_ci "%s port %d MAC: %pM\n", dev->info->name, 71562306a36Sopenharmony_ci port->idx, mac_ee + (port->idx)*8); 71662306a36Sopenharmony_ci memcpy(adap->proposed_mac, mac_ee + (port->idx)*8, 6); 71762306a36Sopenharmony_ci return ret; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic void smi_fe_exit(struct smi_port *port) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci dvb_unregister_frontend(port->fe); 72362306a36Sopenharmony_ci /* remove I2C demod and tuner */ 72462306a36Sopenharmony_ci if (port->i2c_client_tuner) 72562306a36Sopenharmony_ci smi_del_i2c_client(port->i2c_client_tuner); 72662306a36Sopenharmony_ci if (port->i2c_client_demod) 72762306a36Sopenharmony_ci smi_del_i2c_client(port->i2c_client_demod); 72862306a36Sopenharmony_ci dvb_frontend_detach(port->fe); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, 73262306a36Sopenharmony_ci int (*start_feed)(struct dvb_demux_feed *), 73362306a36Sopenharmony_ci int (*stop_feed)(struct dvb_demux_feed *), 73462306a36Sopenharmony_ci void *priv) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci dvbdemux->priv = priv; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci dvbdemux->filternum = 256; 73962306a36Sopenharmony_ci dvbdemux->feednum = 256; 74062306a36Sopenharmony_ci dvbdemux->start_feed = start_feed; 74162306a36Sopenharmony_ci dvbdemux->stop_feed = stop_feed; 74262306a36Sopenharmony_ci dvbdemux->write_to_decoder = NULL; 74362306a36Sopenharmony_ci dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | 74462306a36Sopenharmony_ci DMX_SECTION_FILTERING | 74562306a36Sopenharmony_ci DMX_MEMORY_BASED_FILTERING); 74662306a36Sopenharmony_ci return dvb_dmx_init(dvbdemux); 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, 75062306a36Sopenharmony_ci struct dvb_demux *dvbdemux, 75162306a36Sopenharmony_ci struct dmx_frontend *hw_frontend, 75262306a36Sopenharmony_ci struct dmx_frontend *mem_frontend, 75362306a36Sopenharmony_ci struct dvb_adapter *dvb_adapter) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci int ret; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci dmxdev->filternum = 256; 75862306a36Sopenharmony_ci dmxdev->demux = &dvbdemux->dmx; 75962306a36Sopenharmony_ci dmxdev->capabilities = 0; 76062306a36Sopenharmony_ci ret = dvb_dmxdev_init(dmxdev, dvb_adapter); 76162306a36Sopenharmony_ci if (ret < 0) 76262306a36Sopenharmony_ci return ret; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci hw_frontend->source = DMX_FRONTEND_0; 76562306a36Sopenharmony_ci dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); 76662306a36Sopenharmony_ci mem_frontend->source = DMX_MEMORY_FE; 76762306a36Sopenharmony_ci dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); 76862306a36Sopenharmony_ci return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic u32 smi_config_DMA(struct smi_port *port) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci struct smi_dev *dev = port->dev; 77462306a36Sopenharmony_ci u32 totalLength = 0, dmaMemPtrLow, dmaMemPtrHi, dmaCtlReg; 77562306a36Sopenharmony_ci u8 chanLatencyTimer = 0, dmaChanEnable = 1, dmaTransStart = 1; 77662306a36Sopenharmony_ci u32 dmaManagement = 0, tlpTransUnit = DMA_TRANS_UNIT_188; 77762306a36Sopenharmony_ci u8 tlpTc = 0, tlpTd = 1, tlpEp = 0, tlpAttr = 0; 77862306a36Sopenharmony_ci u64 mem; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci dmaManagement = smi_read(port->DMA_MANAGEMENT); 78162306a36Sopenharmony_ci /* Setup Channel-0 */ 78262306a36Sopenharmony_ci if (port->_dmaInterruptCH0) { 78362306a36Sopenharmony_ci totalLength = SMI_TS_DMA_BUF_SIZE; 78462306a36Sopenharmony_ci mem = port->dma_addr[0]; 78562306a36Sopenharmony_ci dmaMemPtrLow = mem & 0xffffffff; 78662306a36Sopenharmony_ci dmaMemPtrHi = mem >> 32; 78762306a36Sopenharmony_ci dmaCtlReg = (totalLength) | (tlpTransUnit << 22) | (tlpTc << 25) 78862306a36Sopenharmony_ci | (tlpTd << 28) | (tlpEp << 29) | (tlpAttr << 30); 78962306a36Sopenharmony_ci dmaManagement |= dmaChanEnable | (dmaTransStart << 1) 79062306a36Sopenharmony_ci | (chanLatencyTimer << 8); 79162306a36Sopenharmony_ci /* write DMA register, start DMA engine */ 79262306a36Sopenharmony_ci smi_write(port->DMA_CHAN0_ADDR_LOW, dmaMemPtrLow); 79362306a36Sopenharmony_ci smi_write(port->DMA_CHAN0_ADDR_HI, dmaMemPtrHi); 79462306a36Sopenharmony_ci smi_write(port->DMA_CHAN0_CONTROL, dmaCtlReg); 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci /* Setup Channel-1 */ 79762306a36Sopenharmony_ci if (port->_dmaInterruptCH1) { 79862306a36Sopenharmony_ci totalLength = SMI_TS_DMA_BUF_SIZE; 79962306a36Sopenharmony_ci mem = port->dma_addr[1]; 80062306a36Sopenharmony_ci dmaMemPtrLow = mem & 0xffffffff; 80162306a36Sopenharmony_ci dmaMemPtrHi = mem >> 32; 80262306a36Sopenharmony_ci dmaCtlReg = (totalLength) | (tlpTransUnit << 22) | (tlpTc << 25) 80362306a36Sopenharmony_ci | (tlpTd << 28) | (tlpEp << 29) | (tlpAttr << 30); 80462306a36Sopenharmony_ci dmaManagement |= (dmaChanEnable << 16) | (dmaTransStart << 17) 80562306a36Sopenharmony_ci | (chanLatencyTimer << 24); 80662306a36Sopenharmony_ci /* write DMA register, start DMA engine */ 80762306a36Sopenharmony_ci smi_write(port->DMA_CHAN1_ADDR_LOW, dmaMemPtrLow); 80862306a36Sopenharmony_ci smi_write(port->DMA_CHAN1_ADDR_HI, dmaMemPtrHi); 80962306a36Sopenharmony_ci smi_write(port->DMA_CHAN1_CONTROL, dmaCtlReg); 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci return dmaManagement; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic int smi_start_feed(struct dvb_demux_feed *dvbdmxfeed) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 81762306a36Sopenharmony_ci struct smi_port *port = dvbdmx->priv; 81862306a36Sopenharmony_ci struct smi_dev *dev = port->dev; 81962306a36Sopenharmony_ci u32 dmaManagement; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (port->users++ == 0) { 82262306a36Sopenharmony_ci dmaManagement = smi_config_DMA(port); 82362306a36Sopenharmony_ci smi_port_clearInterrupt(port); 82462306a36Sopenharmony_ci smi_port_enableInterrupt(port); 82562306a36Sopenharmony_ci smi_write(port->DMA_MANAGEMENT, dmaManagement); 82662306a36Sopenharmony_ci tasklet_enable(&port->tasklet); 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci return port->users; 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic int smi_stop_feed(struct dvb_demux_feed *dvbdmxfeed) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 83462306a36Sopenharmony_ci struct smi_port *port = dvbdmx->priv; 83562306a36Sopenharmony_ci struct smi_dev *dev = port->dev; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (--port->users) 83862306a36Sopenharmony_ci return port->users; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci tasklet_disable(&port->tasklet); 84162306a36Sopenharmony_ci smi_port_disableInterrupt(port); 84262306a36Sopenharmony_ci smi_clear(port->DMA_MANAGEMENT, 0x30003); 84362306a36Sopenharmony_ci return 0; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic int smi_dvb_init(struct smi_port *port) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci int ret; 84962306a36Sopenharmony_ci struct dvb_adapter *adap = &port->dvb_adapter; 85062306a36Sopenharmony_ci struct dvb_demux *dvbdemux = &port->demux; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci dev_dbg(&port->dev->pci_dev->dev, 85362306a36Sopenharmony_ci "%s, port %d\n", __func__, port->idx); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci ret = dvb_register_adapter(adap, "SMI_DVB", THIS_MODULE, 85662306a36Sopenharmony_ci &port->dev->pci_dev->dev, 85762306a36Sopenharmony_ci adapter_nr); 85862306a36Sopenharmony_ci if (ret < 0) { 85962306a36Sopenharmony_ci dev_err(&port->dev->pci_dev->dev, "Fail to register DVB adapter.\n"); 86062306a36Sopenharmony_ci return ret; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", 86362306a36Sopenharmony_ci smi_start_feed, 86462306a36Sopenharmony_ci smi_stop_feed, port); 86562306a36Sopenharmony_ci if (ret < 0) 86662306a36Sopenharmony_ci goto err_del_dvb_register_adapter; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci ret = my_dvb_dmxdev_ts_card_init(&port->dmxdev, &port->demux, 86962306a36Sopenharmony_ci &port->hw_frontend, 87062306a36Sopenharmony_ci &port->mem_frontend, adap); 87162306a36Sopenharmony_ci if (ret < 0) 87262306a36Sopenharmony_ci goto err_del_dvb_dmx; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci ret = dvb_net_init(adap, &port->dvbnet, port->dmxdev.demux); 87562306a36Sopenharmony_ci if (ret < 0) 87662306a36Sopenharmony_ci goto err_del_dvb_dmxdev; 87762306a36Sopenharmony_ci return 0; 87862306a36Sopenharmony_cierr_del_dvb_dmxdev: 87962306a36Sopenharmony_ci dvbdemux->dmx.close(&dvbdemux->dmx); 88062306a36Sopenharmony_ci dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->hw_frontend); 88162306a36Sopenharmony_ci dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->mem_frontend); 88262306a36Sopenharmony_ci dvb_dmxdev_release(&port->dmxdev); 88362306a36Sopenharmony_cierr_del_dvb_dmx: 88462306a36Sopenharmony_ci dvb_dmx_release(&port->demux); 88562306a36Sopenharmony_cierr_del_dvb_register_adapter: 88662306a36Sopenharmony_ci dvb_unregister_adapter(&port->dvb_adapter); 88762306a36Sopenharmony_ci return ret; 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cistatic void smi_dvb_exit(struct smi_port *port) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci struct dvb_demux *dvbdemux = &port->demux; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci dvb_net_release(&port->dvbnet); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci dvbdemux->dmx.close(&dvbdemux->dmx); 89762306a36Sopenharmony_ci dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->hw_frontend); 89862306a36Sopenharmony_ci dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->mem_frontend); 89962306a36Sopenharmony_ci dvb_dmxdev_release(&port->dmxdev); 90062306a36Sopenharmony_ci dvb_dmx_release(&port->demux); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci dvb_unregister_adapter(&port->dvb_adapter); 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_cistatic int smi_port_attach(struct smi_dev *dev, 90662306a36Sopenharmony_ci struct smi_port *port, int index) 90762306a36Sopenharmony_ci{ 90862306a36Sopenharmony_ci int ret, dmachs; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci port->dev = dev; 91162306a36Sopenharmony_ci port->idx = index; 91262306a36Sopenharmony_ci port->fe_type = (index == 0) ? dev->info->fe_0 : dev->info->fe_1; 91362306a36Sopenharmony_ci dmachs = (index == 0) ? dev->info->ts_0 : dev->info->ts_1; 91462306a36Sopenharmony_ci /* port init.*/ 91562306a36Sopenharmony_ci ret = smi_port_init(port, dmachs); 91662306a36Sopenharmony_ci if (ret < 0) 91762306a36Sopenharmony_ci return ret; 91862306a36Sopenharmony_ci /* dvb init.*/ 91962306a36Sopenharmony_ci ret = smi_dvb_init(port); 92062306a36Sopenharmony_ci if (ret < 0) 92162306a36Sopenharmony_ci goto err_del_port_init; 92262306a36Sopenharmony_ci /* fe init.*/ 92362306a36Sopenharmony_ci ret = smi_fe_init(port); 92462306a36Sopenharmony_ci if (ret < 0) 92562306a36Sopenharmony_ci goto err_del_dvb_init; 92662306a36Sopenharmony_ci return 0; 92762306a36Sopenharmony_cierr_del_dvb_init: 92862306a36Sopenharmony_ci smi_dvb_exit(port); 92962306a36Sopenharmony_cierr_del_port_init: 93062306a36Sopenharmony_ci smi_port_exit(port); 93162306a36Sopenharmony_ci return ret; 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_cistatic void smi_port_detach(struct smi_port *port) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci smi_fe_exit(port); 93762306a36Sopenharmony_ci smi_dvb_exit(port); 93862306a36Sopenharmony_ci smi_port_exit(port); 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cistatic int smi_probe(struct pci_dev *pdev, const struct pci_device_id *id) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci struct smi_dev *dev; 94462306a36Sopenharmony_ci int ret = -ENOMEM; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (pci_enable_device(pdev) < 0) 94762306a36Sopenharmony_ci return -ENODEV; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci dev = kzalloc(sizeof(struct smi_dev), GFP_KERNEL); 95062306a36Sopenharmony_ci if (!dev) { 95162306a36Sopenharmony_ci ret = -ENOMEM; 95262306a36Sopenharmony_ci goto err_pci_disable_device; 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci dev->pci_dev = pdev; 95662306a36Sopenharmony_ci pci_set_drvdata(pdev, dev); 95762306a36Sopenharmony_ci dev->info = (struct smi_cfg_info *) id->driver_data; 95862306a36Sopenharmony_ci dev_info(&dev->pci_dev->dev, 95962306a36Sopenharmony_ci "card detected: %s\n", dev->info->name); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci dev->nr = dev->info->type; 96262306a36Sopenharmony_ci dev->lmmio = ioremap(pci_resource_start(dev->pci_dev, 0), 96362306a36Sopenharmony_ci pci_resource_len(dev->pci_dev, 0)); 96462306a36Sopenharmony_ci if (!dev->lmmio) { 96562306a36Sopenharmony_ci ret = -ENOMEM; 96662306a36Sopenharmony_ci goto err_kfree; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci /* should we set to 32bit DMA? */ 97062306a36Sopenharmony_ci ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 97162306a36Sopenharmony_ci if (ret < 0) 97262306a36Sopenharmony_ci goto err_pci_iounmap; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci pci_set_master(pdev); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci ret = smi_hw_init(dev); 97762306a36Sopenharmony_ci if (ret < 0) 97862306a36Sopenharmony_ci goto err_pci_iounmap; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci ret = smi_i2c_init(dev); 98162306a36Sopenharmony_ci if (ret < 0) 98262306a36Sopenharmony_ci goto err_pci_iounmap; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (dev->info->ts_0) { 98562306a36Sopenharmony_ci ret = smi_port_attach(dev, &dev->ts_port[0], 0); 98662306a36Sopenharmony_ci if (ret < 0) 98762306a36Sopenharmony_ci goto err_del_i2c_adaptor; 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (dev->info->ts_1) { 99162306a36Sopenharmony_ci ret = smi_port_attach(dev, &dev->ts_port[1], 1); 99262306a36Sopenharmony_ci if (ret < 0) 99362306a36Sopenharmony_ci goto err_del_port0_attach; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci ret = smi_ir_init(dev); 99762306a36Sopenharmony_ci if (ret < 0) 99862306a36Sopenharmony_ci goto err_del_port1_attach; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci#ifdef CONFIG_PCI_MSI /* to do msi interrupt.???*/ 100162306a36Sopenharmony_ci if (pci_msi_enabled()) 100262306a36Sopenharmony_ci ret = pci_enable_msi(dev->pci_dev); 100362306a36Sopenharmony_ci if (ret) 100462306a36Sopenharmony_ci dev_info(&dev->pci_dev->dev, "MSI not available.\n"); 100562306a36Sopenharmony_ci#endif 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci ret = request_irq(dev->pci_dev->irq, smi_irq_handler, 100862306a36Sopenharmony_ci IRQF_SHARED, "SMI_PCIE", dev); 100962306a36Sopenharmony_ci if (ret < 0) 101062306a36Sopenharmony_ci goto err_del_ir; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci smi_ir_start(&dev->ir); 101362306a36Sopenharmony_ci return 0; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_cierr_del_ir: 101662306a36Sopenharmony_ci smi_ir_exit(dev); 101762306a36Sopenharmony_cierr_del_port1_attach: 101862306a36Sopenharmony_ci if (dev->info->ts_1) 101962306a36Sopenharmony_ci smi_port_detach(&dev->ts_port[1]); 102062306a36Sopenharmony_cierr_del_port0_attach: 102162306a36Sopenharmony_ci if (dev->info->ts_0) 102262306a36Sopenharmony_ci smi_port_detach(&dev->ts_port[0]); 102362306a36Sopenharmony_cierr_del_i2c_adaptor: 102462306a36Sopenharmony_ci smi_i2c_exit(dev); 102562306a36Sopenharmony_cierr_pci_iounmap: 102662306a36Sopenharmony_ci iounmap(dev->lmmio); 102762306a36Sopenharmony_cierr_kfree: 102862306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 102962306a36Sopenharmony_ci kfree(dev); 103062306a36Sopenharmony_cierr_pci_disable_device: 103162306a36Sopenharmony_ci pci_disable_device(pdev); 103262306a36Sopenharmony_ci return ret; 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_cistatic void smi_remove(struct pci_dev *pdev) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci struct smi_dev *dev = pci_get_drvdata(pdev); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci smi_write(MSI_INT_ENA_CLR, ALL_INT); 104062306a36Sopenharmony_ci free_irq(dev->pci_dev->irq, dev); 104162306a36Sopenharmony_ci#ifdef CONFIG_PCI_MSI 104262306a36Sopenharmony_ci pci_disable_msi(dev->pci_dev); 104362306a36Sopenharmony_ci#endif 104462306a36Sopenharmony_ci if (dev->info->ts_1) 104562306a36Sopenharmony_ci smi_port_detach(&dev->ts_port[1]); 104662306a36Sopenharmony_ci if (dev->info->ts_0) 104762306a36Sopenharmony_ci smi_port_detach(&dev->ts_port[0]); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci smi_ir_exit(dev); 105062306a36Sopenharmony_ci smi_i2c_exit(dev); 105162306a36Sopenharmony_ci iounmap(dev->lmmio); 105262306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 105362306a36Sopenharmony_ci pci_disable_device(pdev); 105462306a36Sopenharmony_ci kfree(dev); 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci/* DVBSky cards */ 105862306a36Sopenharmony_cistatic const struct smi_cfg_info dvbsky_s950_cfg = { 105962306a36Sopenharmony_ci .type = SMI_DVBSKY_S950, 106062306a36Sopenharmony_ci .name = "DVBSky S950 V3", 106162306a36Sopenharmony_ci .ts_0 = SMI_TS_NULL, 106262306a36Sopenharmony_ci .ts_1 = SMI_TS_DMA_BOTH, 106362306a36Sopenharmony_ci .fe_0 = DVBSKY_FE_NULL, 106462306a36Sopenharmony_ci .fe_1 = DVBSKY_FE_M88DS3103, 106562306a36Sopenharmony_ci .rc_map = RC_MAP_DVBSKY, 106662306a36Sopenharmony_ci}; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cistatic const struct smi_cfg_info dvbsky_s952_cfg = { 106962306a36Sopenharmony_ci .type = SMI_DVBSKY_S952, 107062306a36Sopenharmony_ci .name = "DVBSky S952 V3", 107162306a36Sopenharmony_ci .ts_0 = SMI_TS_DMA_BOTH, 107262306a36Sopenharmony_ci .ts_1 = SMI_TS_DMA_BOTH, 107362306a36Sopenharmony_ci .fe_0 = DVBSKY_FE_M88RS6000, 107462306a36Sopenharmony_ci .fe_1 = DVBSKY_FE_M88RS6000, 107562306a36Sopenharmony_ci .rc_map = RC_MAP_DVBSKY, 107662306a36Sopenharmony_ci}; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cistatic const struct smi_cfg_info dvbsky_t9580_cfg = { 107962306a36Sopenharmony_ci .type = SMI_DVBSKY_T9580, 108062306a36Sopenharmony_ci .name = "DVBSky T9580 V3", 108162306a36Sopenharmony_ci .ts_0 = SMI_TS_DMA_BOTH, 108262306a36Sopenharmony_ci .ts_1 = SMI_TS_DMA_BOTH, 108362306a36Sopenharmony_ci .fe_0 = DVBSKY_FE_SIT2, 108462306a36Sopenharmony_ci .fe_1 = DVBSKY_FE_M88DS3103, 108562306a36Sopenharmony_ci .rc_map = RC_MAP_DVBSKY, 108662306a36Sopenharmony_ci}; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_cistatic const struct smi_cfg_info technotrend_s2_4200_cfg = { 108962306a36Sopenharmony_ci .type = SMI_TECHNOTREND_S2_4200, 109062306a36Sopenharmony_ci .name = "TechnoTrend TT-budget S2-4200 Twin", 109162306a36Sopenharmony_ci .ts_0 = SMI_TS_DMA_BOTH, 109262306a36Sopenharmony_ci .ts_1 = SMI_TS_DMA_BOTH, 109362306a36Sopenharmony_ci .fe_0 = DVBSKY_FE_M88RS6000, 109462306a36Sopenharmony_ci .fe_1 = DVBSKY_FE_M88RS6000, 109562306a36Sopenharmony_ci .rc_map = RC_MAP_TT_1500, 109662306a36Sopenharmony_ci}; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci/* PCI IDs */ 109962306a36Sopenharmony_ci#define SMI_ID(_subvend, _subdev, _driverdata) { \ 110062306a36Sopenharmony_ci .vendor = SMI_VID, .device = SMI_PID, \ 110162306a36Sopenharmony_ci .subvendor = _subvend, .subdevice = _subdev, \ 110262306a36Sopenharmony_ci .driver_data = (unsigned long)&_driverdata } 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cistatic const struct pci_device_id smi_id_table[] = { 110562306a36Sopenharmony_ci SMI_ID(0x4254, 0x0550, dvbsky_s950_cfg), 110662306a36Sopenharmony_ci SMI_ID(0x4254, 0x0552, dvbsky_s952_cfg), 110762306a36Sopenharmony_ci SMI_ID(0x4254, 0x5580, dvbsky_t9580_cfg), 110862306a36Sopenharmony_ci SMI_ID(0x13c2, 0x3016, technotrend_s2_4200_cfg), 110962306a36Sopenharmony_ci {0} 111062306a36Sopenharmony_ci}; 111162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, smi_id_table); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic struct pci_driver smipcie_driver = { 111462306a36Sopenharmony_ci .name = "SMI PCIe driver", 111562306a36Sopenharmony_ci .id_table = smi_id_table, 111662306a36Sopenharmony_ci .probe = smi_probe, 111762306a36Sopenharmony_ci .remove = smi_remove, 111862306a36Sopenharmony_ci}; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cimodule_pci_driver(smipcie_driver); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ciMODULE_AUTHOR("Max nibble <nibble.max@gmail.com>"); 112362306a36Sopenharmony_ciMODULE_DESCRIPTION("SMI PCIe driver"); 112462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1125