18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SMI PCIe driver for DVBSky cards. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Max nibble <nibble.max@gmail.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "smipcie.h" 98c2ecf20Sopenharmony_ci#include "m88ds3103.h" 108c2ecf20Sopenharmony_ci#include "ts2020.h" 118c2ecf20Sopenharmony_ci#include "m88rs6000t.h" 128c2ecf20Sopenharmony_ci#include "si2168.h" 138c2ecf20Sopenharmony_ci#include "si2157.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic int smi_hw_init(struct smi_dev *dev) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci u32 port_mux, port_ctrl, int_stat; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci /* set port mux.*/ 228c2ecf20Sopenharmony_ci port_mux = smi_read(MUX_MODE_CTRL); 238c2ecf20Sopenharmony_ci port_mux &= ~(rbPaMSMask); 248c2ecf20Sopenharmony_ci port_mux |= rbPaMSDtvNoGpio; 258c2ecf20Sopenharmony_ci port_mux &= ~(rbPbMSMask); 268c2ecf20Sopenharmony_ci port_mux |= rbPbMSDtvNoGpio; 278c2ecf20Sopenharmony_ci port_mux &= ~(0x0f0000); 288c2ecf20Sopenharmony_ci port_mux |= 0x50000; 298c2ecf20Sopenharmony_ci smi_write(MUX_MODE_CTRL, port_mux); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci /* set DTV register.*/ 328c2ecf20Sopenharmony_ci /* Port A */ 338c2ecf20Sopenharmony_ci port_ctrl = smi_read(VIDEO_CTRL_STATUS_A); 348c2ecf20Sopenharmony_ci port_ctrl &= ~0x01; 358c2ecf20Sopenharmony_ci smi_write(VIDEO_CTRL_STATUS_A, port_ctrl); 368c2ecf20Sopenharmony_ci port_ctrl = smi_read(MPEG2_CTRL_A); 378c2ecf20Sopenharmony_ci port_ctrl &= ~0x40; 388c2ecf20Sopenharmony_ci port_ctrl |= 0x80; 398c2ecf20Sopenharmony_ci smi_write(MPEG2_CTRL_A, port_ctrl); 408c2ecf20Sopenharmony_ci /* Port B */ 418c2ecf20Sopenharmony_ci port_ctrl = smi_read(VIDEO_CTRL_STATUS_B); 428c2ecf20Sopenharmony_ci port_ctrl &= ~0x01; 438c2ecf20Sopenharmony_ci smi_write(VIDEO_CTRL_STATUS_B, port_ctrl); 448c2ecf20Sopenharmony_ci port_ctrl = smi_read(MPEG2_CTRL_B); 458c2ecf20Sopenharmony_ci port_ctrl &= ~0x40; 468c2ecf20Sopenharmony_ci port_ctrl |= 0x80; 478c2ecf20Sopenharmony_ci smi_write(MPEG2_CTRL_B, port_ctrl); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* disable and clear interrupt.*/ 508c2ecf20Sopenharmony_ci smi_write(MSI_INT_ENA_CLR, ALL_INT); 518c2ecf20Sopenharmony_ci int_stat = smi_read(MSI_INT_STATUS); 528c2ecf20Sopenharmony_ci smi_write(MSI_INT_STATUS_CLR, int_stat); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* reset demod.*/ 558c2ecf20Sopenharmony_ci smi_clear(PERIPHERAL_CTRL, 0x0303); 568c2ecf20Sopenharmony_ci msleep(50); 578c2ecf20Sopenharmony_ci smi_set(PERIPHERAL_CTRL, 0x0101); 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* i2c bit bus.*/ 628c2ecf20Sopenharmony_cistatic void smi_i2c_cfg(struct smi_dev *dev, u32 sw_ctl) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci u32 dwCtrl; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci dwCtrl = smi_read(sw_ctl); 678c2ecf20Sopenharmony_ci dwCtrl &= ~0x18; /* disable output.*/ 688c2ecf20Sopenharmony_ci dwCtrl |= 0x21; /* reset and software mode.*/ 698c2ecf20Sopenharmony_ci dwCtrl &= ~0xff00; 708c2ecf20Sopenharmony_ci dwCtrl |= 0x6400; 718c2ecf20Sopenharmony_ci smi_write(sw_ctl, dwCtrl); 728c2ecf20Sopenharmony_ci msleep(20); 738c2ecf20Sopenharmony_ci dwCtrl = smi_read(sw_ctl); 748c2ecf20Sopenharmony_ci dwCtrl &= ~0x20; 758c2ecf20Sopenharmony_ci smi_write(sw_ctl, dwCtrl); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic void smi_i2c_setsda(struct smi_dev *dev, int state, u32 sw_ctl) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci if (state) { 818c2ecf20Sopenharmony_ci /* set as input.*/ 828c2ecf20Sopenharmony_ci smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN); 838c2ecf20Sopenharmony_ci } else { 848c2ecf20Sopenharmony_ci smi_clear(sw_ctl, SW_I2C_MSK_DAT_OUT); 858c2ecf20Sopenharmony_ci /* set as output.*/ 868c2ecf20Sopenharmony_ci smi_set(sw_ctl, SW_I2C_MSK_DAT_EN); 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic void smi_i2c_setscl(void *data, int state, u32 sw_ctl) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct smi_dev *dev = data; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (state) { 958c2ecf20Sopenharmony_ci /* set as input.*/ 968c2ecf20Sopenharmony_ci smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN); 978c2ecf20Sopenharmony_ci } else { 988c2ecf20Sopenharmony_ci smi_clear(sw_ctl, SW_I2C_MSK_CLK_OUT); 998c2ecf20Sopenharmony_ci /* set as output.*/ 1008c2ecf20Sopenharmony_ci smi_set(sw_ctl, SW_I2C_MSK_CLK_EN); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int smi_i2c_getsda(void *data, u32 sw_ctl) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct smi_dev *dev = data; 1078c2ecf20Sopenharmony_ci /* set as input.*/ 1088c2ecf20Sopenharmony_ci smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN); 1098c2ecf20Sopenharmony_ci udelay(1); 1108c2ecf20Sopenharmony_ci return (smi_read(sw_ctl) & SW_I2C_MSK_DAT_IN) ? 1 : 0; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic int smi_i2c_getscl(void *data, u32 sw_ctl) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct smi_dev *dev = data; 1168c2ecf20Sopenharmony_ci /* set as input.*/ 1178c2ecf20Sopenharmony_ci smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN); 1188c2ecf20Sopenharmony_ci udelay(1); 1198c2ecf20Sopenharmony_ci return (smi_read(sw_ctl) & SW_I2C_MSK_CLK_IN) ? 1 : 0; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci/* i2c 0.*/ 1228c2ecf20Sopenharmony_cistatic void smi_i2c0_setsda(void *data, int state) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct smi_dev *dev = data; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci smi_i2c_setsda(dev, state, I2C_A_SW_CTL); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void smi_i2c0_setscl(void *data, int state) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct smi_dev *dev = data; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci smi_i2c_setscl(dev, state, I2C_A_SW_CTL); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int smi_i2c0_getsda(void *data) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct smi_dev *dev = data; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return smi_i2c_getsda(dev, I2C_A_SW_CTL); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int smi_i2c0_getscl(void *data) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct smi_dev *dev = data; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return smi_i2c_getscl(dev, I2C_A_SW_CTL); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci/* i2c 1.*/ 1508c2ecf20Sopenharmony_cistatic void smi_i2c1_setsda(void *data, int state) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct smi_dev *dev = data; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci smi_i2c_setsda(dev, state, I2C_B_SW_CTL); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic void smi_i2c1_setscl(void *data, int state) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct smi_dev *dev = data; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci smi_i2c_setscl(dev, state, I2C_B_SW_CTL); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int smi_i2c1_getsda(void *data) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct smi_dev *dev = data; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return smi_i2c_getsda(dev, I2C_B_SW_CTL); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int smi_i2c1_getscl(void *data) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct smi_dev *dev = data; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci return smi_i2c_getscl(dev, I2C_B_SW_CTL); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic int smi_i2c_init(struct smi_dev *dev) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci int ret; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* i2c bus 0 */ 1838c2ecf20Sopenharmony_ci smi_i2c_cfg(dev, I2C_A_SW_CTL); 1848c2ecf20Sopenharmony_ci i2c_set_adapdata(&dev->i2c_bus[0], dev); 1858c2ecf20Sopenharmony_ci strscpy(dev->i2c_bus[0].name, "SMI-I2C0", sizeof(dev->i2c_bus[0].name)); 1868c2ecf20Sopenharmony_ci dev->i2c_bus[0].owner = THIS_MODULE; 1878c2ecf20Sopenharmony_ci dev->i2c_bus[0].dev.parent = &dev->pci_dev->dev; 1888c2ecf20Sopenharmony_ci dev->i2c_bus[0].algo_data = &dev->i2c_bit[0]; 1898c2ecf20Sopenharmony_ci dev->i2c_bit[0].data = dev; 1908c2ecf20Sopenharmony_ci dev->i2c_bit[0].setsda = smi_i2c0_setsda; 1918c2ecf20Sopenharmony_ci dev->i2c_bit[0].setscl = smi_i2c0_setscl; 1928c2ecf20Sopenharmony_ci dev->i2c_bit[0].getsda = smi_i2c0_getsda; 1938c2ecf20Sopenharmony_ci dev->i2c_bit[0].getscl = smi_i2c0_getscl; 1948c2ecf20Sopenharmony_ci dev->i2c_bit[0].udelay = 12; 1958c2ecf20Sopenharmony_ci dev->i2c_bit[0].timeout = 10; 1968c2ecf20Sopenharmony_ci /* Raise SCL and SDA */ 1978c2ecf20Sopenharmony_ci smi_i2c0_setsda(dev, 1); 1988c2ecf20Sopenharmony_ci smi_i2c0_setscl(dev, 1); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci ret = i2c_bit_add_bus(&dev->i2c_bus[0]); 2018c2ecf20Sopenharmony_ci if (ret < 0) 2028c2ecf20Sopenharmony_ci return ret; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* i2c bus 1 */ 2058c2ecf20Sopenharmony_ci smi_i2c_cfg(dev, I2C_B_SW_CTL); 2068c2ecf20Sopenharmony_ci i2c_set_adapdata(&dev->i2c_bus[1], dev); 2078c2ecf20Sopenharmony_ci strscpy(dev->i2c_bus[1].name, "SMI-I2C1", sizeof(dev->i2c_bus[1].name)); 2088c2ecf20Sopenharmony_ci dev->i2c_bus[1].owner = THIS_MODULE; 2098c2ecf20Sopenharmony_ci dev->i2c_bus[1].dev.parent = &dev->pci_dev->dev; 2108c2ecf20Sopenharmony_ci dev->i2c_bus[1].algo_data = &dev->i2c_bit[1]; 2118c2ecf20Sopenharmony_ci dev->i2c_bit[1].data = dev; 2128c2ecf20Sopenharmony_ci dev->i2c_bit[1].setsda = smi_i2c1_setsda; 2138c2ecf20Sopenharmony_ci dev->i2c_bit[1].setscl = smi_i2c1_setscl; 2148c2ecf20Sopenharmony_ci dev->i2c_bit[1].getsda = smi_i2c1_getsda; 2158c2ecf20Sopenharmony_ci dev->i2c_bit[1].getscl = smi_i2c1_getscl; 2168c2ecf20Sopenharmony_ci dev->i2c_bit[1].udelay = 12; 2178c2ecf20Sopenharmony_ci dev->i2c_bit[1].timeout = 10; 2188c2ecf20Sopenharmony_ci /* Raise SCL and SDA */ 2198c2ecf20Sopenharmony_ci smi_i2c1_setsda(dev, 1); 2208c2ecf20Sopenharmony_ci smi_i2c1_setscl(dev, 1); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci ret = i2c_bit_add_bus(&dev->i2c_bus[1]); 2238c2ecf20Sopenharmony_ci if (ret < 0) 2248c2ecf20Sopenharmony_ci i2c_del_adapter(&dev->i2c_bus[0]); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return ret; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic void smi_i2c_exit(struct smi_dev *dev) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci i2c_del_adapter(&dev->i2c_bus[0]); 2328c2ecf20Sopenharmony_ci i2c_del_adapter(&dev->i2c_bus[1]); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int smi_read_eeprom(struct i2c_adapter *i2c, u16 reg, u8 *data, u16 size) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci int ret; 2388c2ecf20Sopenharmony_ci u8 b0[2] = { (reg >> 8) & 0xff, reg & 0xff }; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci struct i2c_msg msg[] = { 2418c2ecf20Sopenharmony_ci { .addr = 0x50, .flags = 0, 2428c2ecf20Sopenharmony_ci .buf = b0, .len = 2 }, 2438c2ecf20Sopenharmony_ci { .addr = 0x50, .flags = I2C_M_RD, 2448c2ecf20Sopenharmony_ci .buf = data, .len = size } 2458c2ecf20Sopenharmony_ci }; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci ret = i2c_transfer(i2c, msg, 2); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (ret != 2) { 2508c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "%s: reg=0x%x (error=%d)\n", 2518c2ecf20Sopenharmony_ci __func__, reg, ret); 2528c2ecf20Sopenharmony_ci return ret; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci return ret; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/* ts port interrupt operations */ 2588c2ecf20Sopenharmony_cistatic void smi_port_disableInterrupt(struct smi_port *port) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct smi_dev *dev = port->dev; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci smi_write(MSI_INT_ENA_CLR, 2638c2ecf20Sopenharmony_ci (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic void smi_port_enableInterrupt(struct smi_port *port) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct smi_dev *dev = port->dev; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci smi_write(MSI_INT_ENA_SET, 2718c2ecf20Sopenharmony_ci (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic void smi_port_clearInterrupt(struct smi_port *port) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci struct smi_dev *dev = port->dev; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci smi_write(MSI_INT_STATUS_CLR, 2798c2ecf20Sopenharmony_ci (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* tasklet handler: DMA data to dmx.*/ 2838c2ecf20Sopenharmony_cistatic void smi_dma_xfer(struct tasklet_struct *t) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct smi_port *port = from_tasklet(port, t, tasklet); 2868c2ecf20Sopenharmony_ci struct smi_dev *dev = port->dev; 2878c2ecf20Sopenharmony_ci u32 intr_status, finishedData, dmaManagement; 2888c2ecf20Sopenharmony_ci u8 dmaChan0State, dmaChan1State; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci intr_status = port->_int_status; 2918c2ecf20Sopenharmony_ci dmaManagement = smi_read(port->DMA_MANAGEMENT); 2928c2ecf20Sopenharmony_ci dmaChan0State = (u8)((dmaManagement & 0x00000030) >> 4); 2938c2ecf20Sopenharmony_ci dmaChan1State = (u8)((dmaManagement & 0x00300000) >> 20); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* CH-0 DMA interrupt.*/ 2968c2ecf20Sopenharmony_ci if ((intr_status & port->_dmaInterruptCH0) && (dmaChan0State == 0x01)) { 2978c2ecf20Sopenharmony_ci dev_dbg(&dev->pci_dev->dev, 2988c2ecf20Sopenharmony_ci "Port[%d]-DMA CH0 engine complete successful !\n", 2998c2ecf20Sopenharmony_ci port->idx); 3008c2ecf20Sopenharmony_ci finishedData = smi_read(port->DMA_CHAN0_TRANS_STATE); 3018c2ecf20Sopenharmony_ci finishedData &= 0x003FFFFF; 3028c2ecf20Sopenharmony_ci /* value of DMA_PORT0_CHAN0_TRANS_STATE register [21:0] 3038c2ecf20Sopenharmony_ci * indicate dma total transfer length and 3048c2ecf20Sopenharmony_ci * zero of [21:0] indicate dma total transfer length 3058c2ecf20Sopenharmony_ci * equal to 0x400000 (4MB)*/ 3068c2ecf20Sopenharmony_ci if (finishedData == 0) 3078c2ecf20Sopenharmony_ci finishedData = 0x00400000; 3088c2ecf20Sopenharmony_ci if (finishedData != SMI_TS_DMA_BUF_SIZE) { 3098c2ecf20Sopenharmony_ci dev_dbg(&dev->pci_dev->dev, 3108c2ecf20Sopenharmony_ci "DMA CH0 engine complete length mismatched, finish data=%d !\n", 3118c2ecf20Sopenharmony_ci finishedData); 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci dvb_dmx_swfilter_packets(&port->demux, 3148c2ecf20Sopenharmony_ci port->cpu_addr[0], (finishedData / 188)); 3158c2ecf20Sopenharmony_ci /*dvb_dmx_swfilter(&port->demux, 3168c2ecf20Sopenharmony_ci port->cpu_addr[0], finishedData);*/ 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci /* CH-1 DMA interrupt.*/ 3198c2ecf20Sopenharmony_ci if ((intr_status & port->_dmaInterruptCH1) && (dmaChan1State == 0x01)) { 3208c2ecf20Sopenharmony_ci dev_dbg(&dev->pci_dev->dev, 3218c2ecf20Sopenharmony_ci "Port[%d]-DMA CH1 engine complete successful !\n", 3228c2ecf20Sopenharmony_ci port->idx); 3238c2ecf20Sopenharmony_ci finishedData = smi_read(port->DMA_CHAN1_TRANS_STATE); 3248c2ecf20Sopenharmony_ci finishedData &= 0x003FFFFF; 3258c2ecf20Sopenharmony_ci /* value of DMA_PORT0_CHAN0_TRANS_STATE register [21:0] 3268c2ecf20Sopenharmony_ci * indicate dma total transfer length and 3278c2ecf20Sopenharmony_ci * zero of [21:0] indicate dma total transfer length 3288c2ecf20Sopenharmony_ci * equal to 0x400000 (4MB)*/ 3298c2ecf20Sopenharmony_ci if (finishedData == 0) 3308c2ecf20Sopenharmony_ci finishedData = 0x00400000; 3318c2ecf20Sopenharmony_ci if (finishedData != SMI_TS_DMA_BUF_SIZE) { 3328c2ecf20Sopenharmony_ci dev_dbg(&dev->pci_dev->dev, 3338c2ecf20Sopenharmony_ci "DMA CH1 engine complete length mismatched, finish data=%d !\n", 3348c2ecf20Sopenharmony_ci finishedData); 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci dvb_dmx_swfilter_packets(&port->demux, 3378c2ecf20Sopenharmony_ci port->cpu_addr[1], (finishedData / 188)); 3388c2ecf20Sopenharmony_ci /*dvb_dmx_swfilter(&port->demux, 3398c2ecf20Sopenharmony_ci port->cpu_addr[1], finishedData);*/ 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci /* restart DMA.*/ 3428c2ecf20Sopenharmony_ci if (intr_status & port->_dmaInterruptCH0) 3438c2ecf20Sopenharmony_ci dmaManagement |= 0x00000002; 3448c2ecf20Sopenharmony_ci if (intr_status & port->_dmaInterruptCH1) 3458c2ecf20Sopenharmony_ci dmaManagement |= 0x00020000; 3468c2ecf20Sopenharmony_ci smi_write(port->DMA_MANAGEMENT, dmaManagement); 3478c2ecf20Sopenharmony_ci /* Re-enable interrupts */ 3488c2ecf20Sopenharmony_ci smi_port_enableInterrupt(port); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic void smi_port_dma_free(struct smi_port *port) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci if (port->cpu_addr[0]) { 3548c2ecf20Sopenharmony_ci pci_free_consistent(port->dev->pci_dev, SMI_TS_DMA_BUF_SIZE, 3558c2ecf20Sopenharmony_ci port->cpu_addr[0], port->dma_addr[0]); 3568c2ecf20Sopenharmony_ci port->cpu_addr[0] = NULL; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci if (port->cpu_addr[1]) { 3598c2ecf20Sopenharmony_ci pci_free_consistent(port->dev->pci_dev, SMI_TS_DMA_BUF_SIZE, 3608c2ecf20Sopenharmony_ci port->cpu_addr[1], port->dma_addr[1]); 3618c2ecf20Sopenharmony_ci port->cpu_addr[1] = NULL; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int smi_port_init(struct smi_port *port, int dmaChanUsed) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci dev_dbg(&port->dev->pci_dev->dev, 3688c2ecf20Sopenharmony_ci "%s, port %d, dmaused %d\n", __func__, port->idx, dmaChanUsed); 3698c2ecf20Sopenharmony_ci port->enable = 0; 3708c2ecf20Sopenharmony_ci if (port->idx == 0) { 3718c2ecf20Sopenharmony_ci /* Port A */ 3728c2ecf20Sopenharmony_ci port->_dmaInterruptCH0 = dmaChanUsed & 0x01; 3738c2ecf20Sopenharmony_ci port->_dmaInterruptCH1 = dmaChanUsed & 0x02; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci port->DMA_CHAN0_ADDR_LOW = DMA_PORTA_CHAN0_ADDR_LOW; 3768c2ecf20Sopenharmony_ci port->DMA_CHAN0_ADDR_HI = DMA_PORTA_CHAN0_ADDR_HI; 3778c2ecf20Sopenharmony_ci port->DMA_CHAN0_TRANS_STATE = DMA_PORTA_CHAN0_TRANS_STATE; 3788c2ecf20Sopenharmony_ci port->DMA_CHAN0_CONTROL = DMA_PORTA_CHAN0_CONTROL; 3798c2ecf20Sopenharmony_ci port->DMA_CHAN1_ADDR_LOW = DMA_PORTA_CHAN1_ADDR_LOW; 3808c2ecf20Sopenharmony_ci port->DMA_CHAN1_ADDR_HI = DMA_PORTA_CHAN1_ADDR_HI; 3818c2ecf20Sopenharmony_ci port->DMA_CHAN1_TRANS_STATE = DMA_PORTA_CHAN1_TRANS_STATE; 3828c2ecf20Sopenharmony_ci port->DMA_CHAN1_CONTROL = DMA_PORTA_CHAN1_CONTROL; 3838c2ecf20Sopenharmony_ci port->DMA_MANAGEMENT = DMA_PORTA_MANAGEMENT; 3848c2ecf20Sopenharmony_ci } else { 3858c2ecf20Sopenharmony_ci /* Port B */ 3868c2ecf20Sopenharmony_ci port->_dmaInterruptCH0 = (dmaChanUsed << 2) & 0x04; 3878c2ecf20Sopenharmony_ci port->_dmaInterruptCH1 = (dmaChanUsed << 2) & 0x08; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci port->DMA_CHAN0_ADDR_LOW = DMA_PORTB_CHAN0_ADDR_LOW; 3908c2ecf20Sopenharmony_ci port->DMA_CHAN0_ADDR_HI = DMA_PORTB_CHAN0_ADDR_HI; 3918c2ecf20Sopenharmony_ci port->DMA_CHAN0_TRANS_STATE = DMA_PORTB_CHAN0_TRANS_STATE; 3928c2ecf20Sopenharmony_ci port->DMA_CHAN0_CONTROL = DMA_PORTB_CHAN0_CONTROL; 3938c2ecf20Sopenharmony_ci port->DMA_CHAN1_ADDR_LOW = DMA_PORTB_CHAN1_ADDR_LOW; 3948c2ecf20Sopenharmony_ci port->DMA_CHAN1_ADDR_HI = DMA_PORTB_CHAN1_ADDR_HI; 3958c2ecf20Sopenharmony_ci port->DMA_CHAN1_TRANS_STATE = DMA_PORTB_CHAN1_TRANS_STATE; 3968c2ecf20Sopenharmony_ci port->DMA_CHAN1_CONTROL = DMA_PORTB_CHAN1_CONTROL; 3978c2ecf20Sopenharmony_ci port->DMA_MANAGEMENT = DMA_PORTB_MANAGEMENT; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (port->_dmaInterruptCH0) { 4018c2ecf20Sopenharmony_ci port->cpu_addr[0] = pci_alloc_consistent(port->dev->pci_dev, 4028c2ecf20Sopenharmony_ci SMI_TS_DMA_BUF_SIZE, 4038c2ecf20Sopenharmony_ci &port->dma_addr[0]); 4048c2ecf20Sopenharmony_ci if (!port->cpu_addr[0]) { 4058c2ecf20Sopenharmony_ci dev_err(&port->dev->pci_dev->dev, 4068c2ecf20Sopenharmony_ci "Port[%d] DMA CH0 memory allocation failed!\n", 4078c2ecf20Sopenharmony_ci port->idx); 4088c2ecf20Sopenharmony_ci goto err; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (port->_dmaInterruptCH1) { 4138c2ecf20Sopenharmony_ci port->cpu_addr[1] = pci_alloc_consistent(port->dev->pci_dev, 4148c2ecf20Sopenharmony_ci SMI_TS_DMA_BUF_SIZE, 4158c2ecf20Sopenharmony_ci &port->dma_addr[1]); 4168c2ecf20Sopenharmony_ci if (!port->cpu_addr[1]) { 4178c2ecf20Sopenharmony_ci dev_err(&port->dev->pci_dev->dev, 4188c2ecf20Sopenharmony_ci "Port[%d] DMA CH1 memory allocation failed!\n", 4198c2ecf20Sopenharmony_ci port->idx); 4208c2ecf20Sopenharmony_ci goto err; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci smi_port_disableInterrupt(port); 4258c2ecf20Sopenharmony_ci tasklet_setup(&port->tasklet, smi_dma_xfer); 4268c2ecf20Sopenharmony_ci tasklet_disable(&port->tasklet); 4278c2ecf20Sopenharmony_ci port->enable = 1; 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_cierr: 4308c2ecf20Sopenharmony_ci smi_port_dma_free(port); 4318c2ecf20Sopenharmony_ci return -ENOMEM; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic void smi_port_exit(struct smi_port *port) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci smi_port_disableInterrupt(port); 4378c2ecf20Sopenharmony_ci tasklet_kill(&port->tasklet); 4388c2ecf20Sopenharmony_ci smi_port_dma_free(port); 4398c2ecf20Sopenharmony_ci port->enable = 0; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic int smi_port_irq(struct smi_port *port, u32 int_status) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci u32 port_req_irq = port->_dmaInterruptCH0 | port->_dmaInterruptCH1; 4458c2ecf20Sopenharmony_ci int handled = 0; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (int_status & port_req_irq) { 4488c2ecf20Sopenharmony_ci smi_port_disableInterrupt(port); 4498c2ecf20Sopenharmony_ci port->_int_status = int_status; 4508c2ecf20Sopenharmony_ci smi_port_clearInterrupt(port); 4518c2ecf20Sopenharmony_ci tasklet_schedule(&port->tasklet); 4528c2ecf20Sopenharmony_ci handled = 1; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci return handled; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic irqreturn_t smi_irq_handler(int irq, void *dev_id) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct smi_dev *dev = dev_id; 4608c2ecf20Sopenharmony_ci struct smi_port *port0 = &dev->ts_port[0]; 4618c2ecf20Sopenharmony_ci struct smi_port *port1 = &dev->ts_port[1]; 4628c2ecf20Sopenharmony_ci struct smi_rc *ir = &dev->ir; 4638c2ecf20Sopenharmony_ci int handled = 0; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci u32 intr_status = smi_read(MSI_INT_STATUS); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* ts0 interrupt.*/ 4688c2ecf20Sopenharmony_ci if (dev->info->ts_0) 4698c2ecf20Sopenharmony_ci handled += smi_port_irq(port0, intr_status); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* ts1 interrupt.*/ 4728c2ecf20Sopenharmony_ci if (dev->info->ts_1) 4738c2ecf20Sopenharmony_ci handled += smi_port_irq(port1, intr_status); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* ir interrupt.*/ 4768c2ecf20Sopenharmony_ci handled += smi_ir_irq(ir, intr_status); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic struct i2c_client *smi_add_i2c_client(struct i2c_adapter *adapter, 4828c2ecf20Sopenharmony_ci struct i2c_board_info *info) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct i2c_client *client; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci request_module(info->type); 4878c2ecf20Sopenharmony_ci client = i2c_new_client_device(adapter, info); 4888c2ecf20Sopenharmony_ci if (!i2c_client_has_driver(client)) 4898c2ecf20Sopenharmony_ci goto err_add_i2c_client; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (!try_module_get(client->dev.driver->owner)) { 4928c2ecf20Sopenharmony_ci i2c_unregister_device(client); 4938c2ecf20Sopenharmony_ci goto err_add_i2c_client; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci return client; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cierr_add_i2c_client: 4988c2ecf20Sopenharmony_ci client = NULL; 4998c2ecf20Sopenharmony_ci return client; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic void smi_del_i2c_client(struct i2c_client *client) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci module_put(client->dev.driver->owner); 5058c2ecf20Sopenharmony_ci i2c_unregister_device(client); 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic const struct m88ds3103_config smi_dvbsky_m88ds3103_cfg = { 5098c2ecf20Sopenharmony_ci .i2c_addr = 0x68, 5108c2ecf20Sopenharmony_ci .clock = 27000000, 5118c2ecf20Sopenharmony_ci .i2c_wr_max = 33, 5128c2ecf20Sopenharmony_ci .clock_out = 0, 5138c2ecf20Sopenharmony_ci .ts_mode = M88DS3103_TS_PARALLEL, 5148c2ecf20Sopenharmony_ci .ts_clk = 16000, 5158c2ecf20Sopenharmony_ci .ts_clk_pol = 1, 5168c2ecf20Sopenharmony_ci .agc = 0x99, 5178c2ecf20Sopenharmony_ci .lnb_hv_pol = 0, 5188c2ecf20Sopenharmony_ci .lnb_en_pol = 1, 5198c2ecf20Sopenharmony_ci}; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic int smi_dvbsky_m88ds3103_fe_attach(struct smi_port *port) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci int ret = 0; 5248c2ecf20Sopenharmony_ci struct smi_dev *dev = port->dev; 5258c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 5268c2ecf20Sopenharmony_ci /* tuner I2C module */ 5278c2ecf20Sopenharmony_ci struct i2c_adapter *tuner_i2c_adapter; 5288c2ecf20Sopenharmony_ci struct i2c_client *tuner_client; 5298c2ecf20Sopenharmony_ci struct i2c_board_info tuner_info; 5308c2ecf20Sopenharmony_ci struct ts2020_config ts2020_config = {}; 5318c2ecf20Sopenharmony_ci memset(&tuner_info, 0, sizeof(struct i2c_board_info)); 5328c2ecf20Sopenharmony_ci i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* attach demod */ 5358c2ecf20Sopenharmony_ci port->fe = dvb_attach(m88ds3103_attach, 5368c2ecf20Sopenharmony_ci &smi_dvbsky_m88ds3103_cfg, i2c, &tuner_i2c_adapter); 5378c2ecf20Sopenharmony_ci if (!port->fe) { 5388c2ecf20Sopenharmony_ci ret = -ENODEV; 5398c2ecf20Sopenharmony_ci return ret; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci /* attach tuner */ 5428c2ecf20Sopenharmony_ci ts2020_config.fe = port->fe; 5438c2ecf20Sopenharmony_ci strscpy(tuner_info.type, "ts2020", I2C_NAME_SIZE); 5448c2ecf20Sopenharmony_ci tuner_info.addr = 0x60; 5458c2ecf20Sopenharmony_ci tuner_info.platform_data = &ts2020_config; 5468c2ecf20Sopenharmony_ci tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info); 5478c2ecf20Sopenharmony_ci if (!tuner_client) { 5488c2ecf20Sopenharmony_ci ret = -ENODEV; 5498c2ecf20Sopenharmony_ci goto err_tuner_i2c_device; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /* delegate signal strength measurement to tuner */ 5538c2ecf20Sopenharmony_ci port->fe->ops.read_signal_strength = 5548c2ecf20Sopenharmony_ci port->fe->ops.tuner_ops.get_rf_strength; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci port->i2c_client_tuner = tuner_client; 5578c2ecf20Sopenharmony_ci return ret; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cierr_tuner_i2c_device: 5608c2ecf20Sopenharmony_ci dvb_frontend_detach(port->fe); 5618c2ecf20Sopenharmony_ci return ret; 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic const struct m88ds3103_config smi_dvbsky_m88rs6000_cfg = { 5658c2ecf20Sopenharmony_ci .i2c_addr = 0x69, 5668c2ecf20Sopenharmony_ci .clock = 27000000, 5678c2ecf20Sopenharmony_ci .i2c_wr_max = 33, 5688c2ecf20Sopenharmony_ci .ts_mode = M88DS3103_TS_PARALLEL, 5698c2ecf20Sopenharmony_ci .ts_clk = 16000, 5708c2ecf20Sopenharmony_ci .ts_clk_pol = 1, 5718c2ecf20Sopenharmony_ci .agc = 0x99, 5728c2ecf20Sopenharmony_ci .lnb_hv_pol = 0, 5738c2ecf20Sopenharmony_ci .lnb_en_pol = 1, 5748c2ecf20Sopenharmony_ci}; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic int smi_dvbsky_m88rs6000_fe_attach(struct smi_port *port) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci int ret = 0; 5798c2ecf20Sopenharmony_ci struct smi_dev *dev = port->dev; 5808c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 5818c2ecf20Sopenharmony_ci /* tuner I2C module */ 5828c2ecf20Sopenharmony_ci struct i2c_adapter *tuner_i2c_adapter; 5838c2ecf20Sopenharmony_ci struct i2c_client *tuner_client; 5848c2ecf20Sopenharmony_ci struct i2c_board_info tuner_info; 5858c2ecf20Sopenharmony_ci struct m88rs6000t_config m88rs6000t_config; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci memset(&tuner_info, 0, sizeof(struct i2c_board_info)); 5888c2ecf20Sopenharmony_ci i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci /* attach demod */ 5918c2ecf20Sopenharmony_ci port->fe = dvb_attach(m88ds3103_attach, 5928c2ecf20Sopenharmony_ci &smi_dvbsky_m88rs6000_cfg, i2c, &tuner_i2c_adapter); 5938c2ecf20Sopenharmony_ci if (!port->fe) { 5948c2ecf20Sopenharmony_ci ret = -ENODEV; 5958c2ecf20Sopenharmony_ci return ret; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci /* attach tuner */ 5988c2ecf20Sopenharmony_ci m88rs6000t_config.fe = port->fe; 5998c2ecf20Sopenharmony_ci strscpy(tuner_info.type, "m88rs6000t", I2C_NAME_SIZE); 6008c2ecf20Sopenharmony_ci tuner_info.addr = 0x21; 6018c2ecf20Sopenharmony_ci tuner_info.platform_data = &m88rs6000t_config; 6028c2ecf20Sopenharmony_ci tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info); 6038c2ecf20Sopenharmony_ci if (!tuner_client) { 6048c2ecf20Sopenharmony_ci ret = -ENODEV; 6058c2ecf20Sopenharmony_ci goto err_tuner_i2c_device; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci /* delegate signal strength measurement to tuner */ 6098c2ecf20Sopenharmony_ci port->fe->ops.read_signal_strength = 6108c2ecf20Sopenharmony_ci port->fe->ops.tuner_ops.get_rf_strength; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci port->i2c_client_tuner = tuner_client; 6138c2ecf20Sopenharmony_ci return ret; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cierr_tuner_i2c_device: 6168c2ecf20Sopenharmony_ci dvb_frontend_detach(port->fe); 6178c2ecf20Sopenharmony_ci return ret; 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic int smi_dvbsky_sit2_fe_attach(struct smi_port *port) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci int ret = 0; 6238c2ecf20Sopenharmony_ci struct smi_dev *dev = port->dev; 6248c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 6258c2ecf20Sopenharmony_ci struct i2c_adapter *tuner_i2c_adapter; 6268c2ecf20Sopenharmony_ci struct i2c_client *client_tuner, *client_demod; 6278c2ecf20Sopenharmony_ci struct i2c_board_info client_info; 6288c2ecf20Sopenharmony_ci struct si2168_config si2168_config; 6298c2ecf20Sopenharmony_ci struct si2157_config si2157_config; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* select i2c bus */ 6328c2ecf20Sopenharmony_ci i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* attach demod */ 6358c2ecf20Sopenharmony_ci memset(&si2168_config, 0, sizeof(si2168_config)); 6368c2ecf20Sopenharmony_ci si2168_config.i2c_adapter = &tuner_i2c_adapter; 6378c2ecf20Sopenharmony_ci si2168_config.fe = &port->fe; 6388c2ecf20Sopenharmony_ci si2168_config.ts_mode = SI2168_TS_PARALLEL; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci memset(&client_info, 0, sizeof(struct i2c_board_info)); 6418c2ecf20Sopenharmony_ci strscpy(client_info.type, "si2168", I2C_NAME_SIZE); 6428c2ecf20Sopenharmony_ci client_info.addr = 0x64; 6438c2ecf20Sopenharmony_ci client_info.platform_data = &si2168_config; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci client_demod = smi_add_i2c_client(i2c, &client_info); 6468c2ecf20Sopenharmony_ci if (!client_demod) { 6478c2ecf20Sopenharmony_ci ret = -ENODEV; 6488c2ecf20Sopenharmony_ci return ret; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci port->i2c_client_demod = client_demod; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci /* attach tuner */ 6538c2ecf20Sopenharmony_ci memset(&si2157_config, 0, sizeof(si2157_config)); 6548c2ecf20Sopenharmony_ci si2157_config.fe = port->fe; 6558c2ecf20Sopenharmony_ci si2157_config.if_port = 1; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci memset(&client_info, 0, sizeof(struct i2c_board_info)); 6588c2ecf20Sopenharmony_ci strscpy(client_info.type, "si2157", I2C_NAME_SIZE); 6598c2ecf20Sopenharmony_ci client_info.addr = 0x60; 6608c2ecf20Sopenharmony_ci client_info.platform_data = &si2157_config; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci client_tuner = smi_add_i2c_client(tuner_i2c_adapter, &client_info); 6638c2ecf20Sopenharmony_ci if (!client_tuner) { 6648c2ecf20Sopenharmony_ci smi_del_i2c_client(port->i2c_client_demod); 6658c2ecf20Sopenharmony_ci port->i2c_client_demod = NULL; 6668c2ecf20Sopenharmony_ci ret = -ENODEV; 6678c2ecf20Sopenharmony_ci return ret; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci port->i2c_client_tuner = client_tuner; 6708c2ecf20Sopenharmony_ci return ret; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic int smi_fe_init(struct smi_port *port) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci int ret = 0; 6768c2ecf20Sopenharmony_ci struct smi_dev *dev = port->dev; 6778c2ecf20Sopenharmony_ci struct dvb_adapter *adap = &port->dvb_adapter; 6788c2ecf20Sopenharmony_ci u8 mac_ee[16]; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci dev_dbg(&port->dev->pci_dev->dev, 6818c2ecf20Sopenharmony_ci "%s: port %d, fe_type = %d\n", 6828c2ecf20Sopenharmony_ci __func__, port->idx, port->fe_type); 6838c2ecf20Sopenharmony_ci switch (port->fe_type) { 6848c2ecf20Sopenharmony_ci case DVBSKY_FE_M88DS3103: 6858c2ecf20Sopenharmony_ci ret = smi_dvbsky_m88ds3103_fe_attach(port); 6868c2ecf20Sopenharmony_ci break; 6878c2ecf20Sopenharmony_ci case DVBSKY_FE_M88RS6000: 6888c2ecf20Sopenharmony_ci ret = smi_dvbsky_m88rs6000_fe_attach(port); 6898c2ecf20Sopenharmony_ci break; 6908c2ecf20Sopenharmony_ci case DVBSKY_FE_SIT2: 6918c2ecf20Sopenharmony_ci ret = smi_dvbsky_sit2_fe_attach(port); 6928c2ecf20Sopenharmony_ci break; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci if (ret < 0) 6958c2ecf20Sopenharmony_ci return ret; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* register dvb frontend */ 6988c2ecf20Sopenharmony_ci ret = dvb_register_frontend(adap, port->fe); 6998c2ecf20Sopenharmony_ci if (ret < 0) { 7008c2ecf20Sopenharmony_ci if (port->i2c_client_tuner) 7018c2ecf20Sopenharmony_ci smi_del_i2c_client(port->i2c_client_tuner); 7028c2ecf20Sopenharmony_ci if (port->i2c_client_demod) 7038c2ecf20Sopenharmony_ci smi_del_i2c_client(port->i2c_client_demod); 7048c2ecf20Sopenharmony_ci dvb_frontend_detach(port->fe); 7058c2ecf20Sopenharmony_ci return ret; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci /* init MAC.*/ 7088c2ecf20Sopenharmony_ci ret = smi_read_eeprom(&dev->i2c_bus[0], 0xc0, mac_ee, 16); 7098c2ecf20Sopenharmony_ci dev_info(&port->dev->pci_dev->dev, 7108c2ecf20Sopenharmony_ci "%s port %d MAC: %pM\n", dev->info->name, 7118c2ecf20Sopenharmony_ci port->idx, mac_ee + (port->idx)*8); 7128c2ecf20Sopenharmony_ci memcpy(adap->proposed_mac, mac_ee + (port->idx)*8, 6); 7138c2ecf20Sopenharmony_ci return ret; 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic void smi_fe_exit(struct smi_port *port) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci dvb_unregister_frontend(port->fe); 7198c2ecf20Sopenharmony_ci /* remove I2C demod and tuner */ 7208c2ecf20Sopenharmony_ci if (port->i2c_client_tuner) 7218c2ecf20Sopenharmony_ci smi_del_i2c_client(port->i2c_client_tuner); 7228c2ecf20Sopenharmony_ci if (port->i2c_client_demod) 7238c2ecf20Sopenharmony_ci smi_del_i2c_client(port->i2c_client_demod); 7248c2ecf20Sopenharmony_ci dvb_frontend_detach(port->fe); 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, 7288c2ecf20Sopenharmony_ci int (*start_feed)(struct dvb_demux_feed *), 7298c2ecf20Sopenharmony_ci int (*stop_feed)(struct dvb_demux_feed *), 7308c2ecf20Sopenharmony_ci void *priv) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci dvbdemux->priv = priv; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci dvbdemux->filternum = 256; 7358c2ecf20Sopenharmony_ci dvbdemux->feednum = 256; 7368c2ecf20Sopenharmony_ci dvbdemux->start_feed = start_feed; 7378c2ecf20Sopenharmony_ci dvbdemux->stop_feed = stop_feed; 7388c2ecf20Sopenharmony_ci dvbdemux->write_to_decoder = NULL; 7398c2ecf20Sopenharmony_ci dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | 7408c2ecf20Sopenharmony_ci DMX_SECTION_FILTERING | 7418c2ecf20Sopenharmony_ci DMX_MEMORY_BASED_FILTERING); 7428c2ecf20Sopenharmony_ci return dvb_dmx_init(dvbdemux); 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, 7468c2ecf20Sopenharmony_ci struct dvb_demux *dvbdemux, 7478c2ecf20Sopenharmony_ci struct dmx_frontend *hw_frontend, 7488c2ecf20Sopenharmony_ci struct dmx_frontend *mem_frontend, 7498c2ecf20Sopenharmony_ci struct dvb_adapter *dvb_adapter) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci int ret; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci dmxdev->filternum = 256; 7548c2ecf20Sopenharmony_ci dmxdev->demux = &dvbdemux->dmx; 7558c2ecf20Sopenharmony_ci dmxdev->capabilities = 0; 7568c2ecf20Sopenharmony_ci ret = dvb_dmxdev_init(dmxdev, dvb_adapter); 7578c2ecf20Sopenharmony_ci if (ret < 0) 7588c2ecf20Sopenharmony_ci return ret; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci hw_frontend->source = DMX_FRONTEND_0; 7618c2ecf20Sopenharmony_ci dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); 7628c2ecf20Sopenharmony_ci mem_frontend->source = DMX_MEMORY_FE; 7638c2ecf20Sopenharmony_ci dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); 7648c2ecf20Sopenharmony_ci return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic u32 smi_config_DMA(struct smi_port *port) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci struct smi_dev *dev = port->dev; 7708c2ecf20Sopenharmony_ci u32 totalLength = 0, dmaMemPtrLow, dmaMemPtrHi, dmaCtlReg; 7718c2ecf20Sopenharmony_ci u8 chanLatencyTimer = 0, dmaChanEnable = 1, dmaTransStart = 1; 7728c2ecf20Sopenharmony_ci u32 dmaManagement = 0, tlpTransUnit = DMA_TRANS_UNIT_188; 7738c2ecf20Sopenharmony_ci u8 tlpTc = 0, tlpTd = 1, tlpEp = 0, tlpAttr = 0; 7748c2ecf20Sopenharmony_ci u64 mem; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci dmaManagement = smi_read(port->DMA_MANAGEMENT); 7778c2ecf20Sopenharmony_ci /* Setup Channel-0 */ 7788c2ecf20Sopenharmony_ci if (port->_dmaInterruptCH0) { 7798c2ecf20Sopenharmony_ci totalLength = SMI_TS_DMA_BUF_SIZE; 7808c2ecf20Sopenharmony_ci mem = port->dma_addr[0]; 7818c2ecf20Sopenharmony_ci dmaMemPtrLow = mem & 0xffffffff; 7828c2ecf20Sopenharmony_ci dmaMemPtrHi = mem >> 32; 7838c2ecf20Sopenharmony_ci dmaCtlReg = (totalLength) | (tlpTransUnit << 22) | (tlpTc << 25) 7848c2ecf20Sopenharmony_ci | (tlpTd << 28) | (tlpEp << 29) | (tlpAttr << 30); 7858c2ecf20Sopenharmony_ci dmaManagement |= dmaChanEnable | (dmaTransStart << 1) 7868c2ecf20Sopenharmony_ci | (chanLatencyTimer << 8); 7878c2ecf20Sopenharmony_ci /* write DMA register, start DMA engine */ 7888c2ecf20Sopenharmony_ci smi_write(port->DMA_CHAN0_ADDR_LOW, dmaMemPtrLow); 7898c2ecf20Sopenharmony_ci smi_write(port->DMA_CHAN0_ADDR_HI, dmaMemPtrHi); 7908c2ecf20Sopenharmony_ci smi_write(port->DMA_CHAN0_CONTROL, dmaCtlReg); 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci /* Setup Channel-1 */ 7938c2ecf20Sopenharmony_ci if (port->_dmaInterruptCH1) { 7948c2ecf20Sopenharmony_ci totalLength = SMI_TS_DMA_BUF_SIZE; 7958c2ecf20Sopenharmony_ci mem = port->dma_addr[1]; 7968c2ecf20Sopenharmony_ci dmaMemPtrLow = mem & 0xffffffff; 7978c2ecf20Sopenharmony_ci dmaMemPtrHi = mem >> 32; 7988c2ecf20Sopenharmony_ci dmaCtlReg = (totalLength) | (tlpTransUnit << 22) | (tlpTc << 25) 7998c2ecf20Sopenharmony_ci | (tlpTd << 28) | (tlpEp << 29) | (tlpAttr << 30); 8008c2ecf20Sopenharmony_ci dmaManagement |= (dmaChanEnable << 16) | (dmaTransStart << 17) 8018c2ecf20Sopenharmony_ci | (chanLatencyTimer << 24); 8028c2ecf20Sopenharmony_ci /* write DMA register, start DMA engine */ 8038c2ecf20Sopenharmony_ci smi_write(port->DMA_CHAN1_ADDR_LOW, dmaMemPtrLow); 8048c2ecf20Sopenharmony_ci smi_write(port->DMA_CHAN1_ADDR_HI, dmaMemPtrHi); 8058c2ecf20Sopenharmony_ci smi_write(port->DMA_CHAN1_CONTROL, dmaCtlReg); 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci return dmaManagement; 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic int smi_start_feed(struct dvb_demux_feed *dvbdmxfeed) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 8138c2ecf20Sopenharmony_ci struct smi_port *port = dvbdmx->priv; 8148c2ecf20Sopenharmony_ci struct smi_dev *dev = port->dev; 8158c2ecf20Sopenharmony_ci u32 dmaManagement; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (port->users++ == 0) { 8188c2ecf20Sopenharmony_ci dmaManagement = smi_config_DMA(port); 8198c2ecf20Sopenharmony_ci smi_port_clearInterrupt(port); 8208c2ecf20Sopenharmony_ci smi_port_enableInterrupt(port); 8218c2ecf20Sopenharmony_ci smi_write(port->DMA_MANAGEMENT, dmaManagement); 8228c2ecf20Sopenharmony_ci tasklet_enable(&port->tasklet); 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci return port->users; 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_cistatic int smi_stop_feed(struct dvb_demux_feed *dvbdmxfeed) 8288c2ecf20Sopenharmony_ci{ 8298c2ecf20Sopenharmony_ci struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 8308c2ecf20Sopenharmony_ci struct smi_port *port = dvbdmx->priv; 8318c2ecf20Sopenharmony_ci struct smi_dev *dev = port->dev; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (--port->users) 8348c2ecf20Sopenharmony_ci return port->users; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci tasklet_disable(&port->tasklet); 8378c2ecf20Sopenharmony_ci smi_port_disableInterrupt(port); 8388c2ecf20Sopenharmony_ci smi_clear(port->DMA_MANAGEMENT, 0x30003); 8398c2ecf20Sopenharmony_ci return 0; 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic int smi_dvb_init(struct smi_port *port) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci int ret; 8458c2ecf20Sopenharmony_ci struct dvb_adapter *adap = &port->dvb_adapter; 8468c2ecf20Sopenharmony_ci struct dvb_demux *dvbdemux = &port->demux; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci dev_dbg(&port->dev->pci_dev->dev, 8498c2ecf20Sopenharmony_ci "%s, port %d\n", __func__, port->idx); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci ret = dvb_register_adapter(adap, "SMI_DVB", THIS_MODULE, 8528c2ecf20Sopenharmony_ci &port->dev->pci_dev->dev, 8538c2ecf20Sopenharmony_ci adapter_nr); 8548c2ecf20Sopenharmony_ci if (ret < 0) { 8558c2ecf20Sopenharmony_ci dev_err(&port->dev->pci_dev->dev, "Fail to register DVB adapter.\n"); 8568c2ecf20Sopenharmony_ci return ret; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", 8598c2ecf20Sopenharmony_ci smi_start_feed, 8608c2ecf20Sopenharmony_ci smi_stop_feed, port); 8618c2ecf20Sopenharmony_ci if (ret < 0) 8628c2ecf20Sopenharmony_ci goto err_del_dvb_register_adapter; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci ret = my_dvb_dmxdev_ts_card_init(&port->dmxdev, &port->demux, 8658c2ecf20Sopenharmony_ci &port->hw_frontend, 8668c2ecf20Sopenharmony_ci &port->mem_frontend, adap); 8678c2ecf20Sopenharmony_ci if (ret < 0) 8688c2ecf20Sopenharmony_ci goto err_del_dvb_dmx; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci ret = dvb_net_init(adap, &port->dvbnet, port->dmxdev.demux); 8718c2ecf20Sopenharmony_ci if (ret < 0) 8728c2ecf20Sopenharmony_ci goto err_del_dvb_dmxdev; 8738c2ecf20Sopenharmony_ci return 0; 8748c2ecf20Sopenharmony_cierr_del_dvb_dmxdev: 8758c2ecf20Sopenharmony_ci dvbdemux->dmx.close(&dvbdemux->dmx); 8768c2ecf20Sopenharmony_ci dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->hw_frontend); 8778c2ecf20Sopenharmony_ci dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->mem_frontend); 8788c2ecf20Sopenharmony_ci dvb_dmxdev_release(&port->dmxdev); 8798c2ecf20Sopenharmony_cierr_del_dvb_dmx: 8808c2ecf20Sopenharmony_ci dvb_dmx_release(&port->demux); 8818c2ecf20Sopenharmony_cierr_del_dvb_register_adapter: 8828c2ecf20Sopenharmony_ci dvb_unregister_adapter(&port->dvb_adapter); 8838c2ecf20Sopenharmony_ci return ret; 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic void smi_dvb_exit(struct smi_port *port) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci struct dvb_demux *dvbdemux = &port->demux; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci dvb_net_release(&port->dvbnet); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci dvbdemux->dmx.close(&dvbdemux->dmx); 8938c2ecf20Sopenharmony_ci dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->hw_frontend); 8948c2ecf20Sopenharmony_ci dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->mem_frontend); 8958c2ecf20Sopenharmony_ci dvb_dmxdev_release(&port->dmxdev); 8968c2ecf20Sopenharmony_ci dvb_dmx_release(&port->demux); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci dvb_unregister_adapter(&port->dvb_adapter); 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic int smi_port_attach(struct smi_dev *dev, 9028c2ecf20Sopenharmony_ci struct smi_port *port, int index) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci int ret, dmachs; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci port->dev = dev; 9078c2ecf20Sopenharmony_ci port->idx = index; 9088c2ecf20Sopenharmony_ci port->fe_type = (index == 0) ? dev->info->fe_0 : dev->info->fe_1; 9098c2ecf20Sopenharmony_ci dmachs = (index == 0) ? dev->info->ts_0 : dev->info->ts_1; 9108c2ecf20Sopenharmony_ci /* port init.*/ 9118c2ecf20Sopenharmony_ci ret = smi_port_init(port, dmachs); 9128c2ecf20Sopenharmony_ci if (ret < 0) 9138c2ecf20Sopenharmony_ci return ret; 9148c2ecf20Sopenharmony_ci /* dvb init.*/ 9158c2ecf20Sopenharmony_ci ret = smi_dvb_init(port); 9168c2ecf20Sopenharmony_ci if (ret < 0) 9178c2ecf20Sopenharmony_ci goto err_del_port_init; 9188c2ecf20Sopenharmony_ci /* fe init.*/ 9198c2ecf20Sopenharmony_ci ret = smi_fe_init(port); 9208c2ecf20Sopenharmony_ci if (ret < 0) 9218c2ecf20Sopenharmony_ci goto err_del_dvb_init; 9228c2ecf20Sopenharmony_ci return 0; 9238c2ecf20Sopenharmony_cierr_del_dvb_init: 9248c2ecf20Sopenharmony_ci smi_dvb_exit(port); 9258c2ecf20Sopenharmony_cierr_del_port_init: 9268c2ecf20Sopenharmony_ci smi_port_exit(port); 9278c2ecf20Sopenharmony_ci return ret; 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic void smi_port_detach(struct smi_port *port) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci smi_fe_exit(port); 9338c2ecf20Sopenharmony_ci smi_dvb_exit(port); 9348c2ecf20Sopenharmony_ci smi_port_exit(port); 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic int smi_probe(struct pci_dev *pdev, const struct pci_device_id *id) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci struct smi_dev *dev; 9408c2ecf20Sopenharmony_ci int ret = -ENOMEM; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (pci_enable_device(pdev) < 0) 9438c2ecf20Sopenharmony_ci return -ENODEV; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(struct smi_dev), GFP_KERNEL); 9468c2ecf20Sopenharmony_ci if (!dev) { 9478c2ecf20Sopenharmony_ci ret = -ENOMEM; 9488c2ecf20Sopenharmony_ci goto err_pci_disable_device; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci dev->pci_dev = pdev; 9528c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, dev); 9538c2ecf20Sopenharmony_ci dev->info = (struct smi_cfg_info *) id->driver_data; 9548c2ecf20Sopenharmony_ci dev_info(&dev->pci_dev->dev, 9558c2ecf20Sopenharmony_ci "card detected: %s\n", dev->info->name); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci dev->nr = dev->info->type; 9588c2ecf20Sopenharmony_ci dev->lmmio = ioremap(pci_resource_start(dev->pci_dev, 0), 9598c2ecf20Sopenharmony_ci pci_resource_len(dev->pci_dev, 0)); 9608c2ecf20Sopenharmony_ci if (!dev->lmmio) { 9618c2ecf20Sopenharmony_ci ret = -ENOMEM; 9628c2ecf20Sopenharmony_ci goto err_kfree; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci /* should we set to 32bit DMA? */ 9668c2ecf20Sopenharmony_ci ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 9678c2ecf20Sopenharmony_ci if (ret < 0) 9688c2ecf20Sopenharmony_ci goto err_pci_iounmap; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci pci_set_master(pdev); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci ret = smi_hw_init(dev); 9738c2ecf20Sopenharmony_ci if (ret < 0) 9748c2ecf20Sopenharmony_ci goto err_pci_iounmap; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci ret = smi_i2c_init(dev); 9778c2ecf20Sopenharmony_ci if (ret < 0) 9788c2ecf20Sopenharmony_ci goto err_pci_iounmap; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (dev->info->ts_0) { 9818c2ecf20Sopenharmony_ci ret = smi_port_attach(dev, &dev->ts_port[0], 0); 9828c2ecf20Sopenharmony_ci if (ret < 0) 9838c2ecf20Sopenharmony_ci goto err_del_i2c_adaptor; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (dev->info->ts_1) { 9878c2ecf20Sopenharmony_ci ret = smi_port_attach(dev, &dev->ts_port[1], 1); 9888c2ecf20Sopenharmony_ci if (ret < 0) 9898c2ecf20Sopenharmony_ci goto err_del_port0_attach; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci ret = smi_ir_init(dev); 9938c2ecf20Sopenharmony_ci if (ret < 0) 9948c2ecf20Sopenharmony_ci goto err_del_port1_attach; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_MSI /* to do msi interrupt.???*/ 9978c2ecf20Sopenharmony_ci if (pci_msi_enabled()) 9988c2ecf20Sopenharmony_ci ret = pci_enable_msi(dev->pci_dev); 9998c2ecf20Sopenharmony_ci if (ret) 10008c2ecf20Sopenharmony_ci dev_info(&dev->pci_dev->dev, "MSI not available.\n"); 10018c2ecf20Sopenharmony_ci#endif 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci ret = request_irq(dev->pci_dev->irq, smi_irq_handler, 10048c2ecf20Sopenharmony_ci IRQF_SHARED, "SMI_PCIE", dev); 10058c2ecf20Sopenharmony_ci if (ret < 0) 10068c2ecf20Sopenharmony_ci goto err_del_ir; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci smi_ir_start(&dev->ir); 10098c2ecf20Sopenharmony_ci return 0; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cierr_del_ir: 10128c2ecf20Sopenharmony_ci smi_ir_exit(dev); 10138c2ecf20Sopenharmony_cierr_del_port1_attach: 10148c2ecf20Sopenharmony_ci if (dev->info->ts_1) 10158c2ecf20Sopenharmony_ci smi_port_detach(&dev->ts_port[1]); 10168c2ecf20Sopenharmony_cierr_del_port0_attach: 10178c2ecf20Sopenharmony_ci if (dev->info->ts_0) 10188c2ecf20Sopenharmony_ci smi_port_detach(&dev->ts_port[0]); 10198c2ecf20Sopenharmony_cierr_del_i2c_adaptor: 10208c2ecf20Sopenharmony_ci smi_i2c_exit(dev); 10218c2ecf20Sopenharmony_cierr_pci_iounmap: 10228c2ecf20Sopenharmony_ci iounmap(dev->lmmio); 10238c2ecf20Sopenharmony_cierr_kfree: 10248c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 10258c2ecf20Sopenharmony_ci kfree(dev); 10268c2ecf20Sopenharmony_cierr_pci_disable_device: 10278c2ecf20Sopenharmony_ci pci_disable_device(pdev); 10288c2ecf20Sopenharmony_ci return ret; 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_cistatic void smi_remove(struct pci_dev *pdev) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci struct smi_dev *dev = pci_get_drvdata(pdev); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci smi_write(MSI_INT_ENA_CLR, ALL_INT); 10368c2ecf20Sopenharmony_ci free_irq(dev->pci_dev->irq, dev); 10378c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_MSI 10388c2ecf20Sopenharmony_ci pci_disable_msi(dev->pci_dev); 10398c2ecf20Sopenharmony_ci#endif 10408c2ecf20Sopenharmony_ci if (dev->info->ts_1) 10418c2ecf20Sopenharmony_ci smi_port_detach(&dev->ts_port[1]); 10428c2ecf20Sopenharmony_ci if (dev->info->ts_0) 10438c2ecf20Sopenharmony_ci smi_port_detach(&dev->ts_port[0]); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci smi_ir_exit(dev); 10468c2ecf20Sopenharmony_ci smi_i2c_exit(dev); 10478c2ecf20Sopenharmony_ci iounmap(dev->lmmio); 10488c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 10498c2ecf20Sopenharmony_ci pci_disable_device(pdev); 10508c2ecf20Sopenharmony_ci kfree(dev); 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci/* DVBSky cards */ 10548c2ecf20Sopenharmony_cistatic const struct smi_cfg_info dvbsky_s950_cfg = { 10558c2ecf20Sopenharmony_ci .type = SMI_DVBSKY_S950, 10568c2ecf20Sopenharmony_ci .name = "DVBSky S950 V3", 10578c2ecf20Sopenharmony_ci .ts_0 = SMI_TS_NULL, 10588c2ecf20Sopenharmony_ci .ts_1 = SMI_TS_DMA_BOTH, 10598c2ecf20Sopenharmony_ci .fe_0 = DVBSKY_FE_NULL, 10608c2ecf20Sopenharmony_ci .fe_1 = DVBSKY_FE_M88DS3103, 10618c2ecf20Sopenharmony_ci .rc_map = RC_MAP_DVBSKY, 10628c2ecf20Sopenharmony_ci}; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cistatic const struct smi_cfg_info dvbsky_s952_cfg = { 10658c2ecf20Sopenharmony_ci .type = SMI_DVBSKY_S952, 10668c2ecf20Sopenharmony_ci .name = "DVBSky S952 V3", 10678c2ecf20Sopenharmony_ci .ts_0 = SMI_TS_DMA_BOTH, 10688c2ecf20Sopenharmony_ci .ts_1 = SMI_TS_DMA_BOTH, 10698c2ecf20Sopenharmony_ci .fe_0 = DVBSKY_FE_M88RS6000, 10708c2ecf20Sopenharmony_ci .fe_1 = DVBSKY_FE_M88RS6000, 10718c2ecf20Sopenharmony_ci .rc_map = RC_MAP_DVBSKY, 10728c2ecf20Sopenharmony_ci}; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_cistatic const struct smi_cfg_info dvbsky_t9580_cfg = { 10758c2ecf20Sopenharmony_ci .type = SMI_DVBSKY_T9580, 10768c2ecf20Sopenharmony_ci .name = "DVBSky T9580 V3", 10778c2ecf20Sopenharmony_ci .ts_0 = SMI_TS_DMA_BOTH, 10788c2ecf20Sopenharmony_ci .ts_1 = SMI_TS_DMA_BOTH, 10798c2ecf20Sopenharmony_ci .fe_0 = DVBSKY_FE_SIT2, 10808c2ecf20Sopenharmony_ci .fe_1 = DVBSKY_FE_M88DS3103, 10818c2ecf20Sopenharmony_ci .rc_map = RC_MAP_DVBSKY, 10828c2ecf20Sopenharmony_ci}; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_cistatic const struct smi_cfg_info technotrend_s2_4200_cfg = { 10858c2ecf20Sopenharmony_ci .type = SMI_TECHNOTREND_S2_4200, 10868c2ecf20Sopenharmony_ci .name = "TechnoTrend TT-budget S2-4200 Twin", 10878c2ecf20Sopenharmony_ci .ts_0 = SMI_TS_DMA_BOTH, 10888c2ecf20Sopenharmony_ci .ts_1 = SMI_TS_DMA_BOTH, 10898c2ecf20Sopenharmony_ci .fe_0 = DVBSKY_FE_M88RS6000, 10908c2ecf20Sopenharmony_ci .fe_1 = DVBSKY_FE_M88RS6000, 10918c2ecf20Sopenharmony_ci .rc_map = RC_MAP_TT_1500, 10928c2ecf20Sopenharmony_ci}; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci/* PCI IDs */ 10958c2ecf20Sopenharmony_ci#define SMI_ID(_subvend, _subdev, _driverdata) { \ 10968c2ecf20Sopenharmony_ci .vendor = SMI_VID, .device = SMI_PID, \ 10978c2ecf20Sopenharmony_ci .subvendor = _subvend, .subdevice = _subdev, \ 10988c2ecf20Sopenharmony_ci .driver_data = (unsigned long)&_driverdata } 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_cistatic const struct pci_device_id smi_id_table[] = { 11018c2ecf20Sopenharmony_ci SMI_ID(0x4254, 0x0550, dvbsky_s950_cfg), 11028c2ecf20Sopenharmony_ci SMI_ID(0x4254, 0x0552, dvbsky_s952_cfg), 11038c2ecf20Sopenharmony_ci SMI_ID(0x4254, 0x5580, dvbsky_t9580_cfg), 11048c2ecf20Sopenharmony_ci SMI_ID(0x13c2, 0x3016, technotrend_s2_4200_cfg), 11058c2ecf20Sopenharmony_ci {0} 11068c2ecf20Sopenharmony_ci}; 11078c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, smi_id_table); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistatic struct pci_driver smipcie_driver = { 11108c2ecf20Sopenharmony_ci .name = "SMI PCIe driver", 11118c2ecf20Sopenharmony_ci .id_table = smi_id_table, 11128c2ecf20Sopenharmony_ci .probe = smi_probe, 11138c2ecf20Sopenharmony_ci .remove = smi_remove, 11148c2ecf20Sopenharmony_ci}; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cimodule_pci_driver(smipcie_driver); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Max nibble <nibble.max@gmail.com>"); 11198c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SMI PCIe driver"); 11208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1121