125aee3deSMauro Carvalho Chehab /* 225aee3deSMauro Carvalho Chehab Hopper PCI bridge driver 325aee3deSMauro Carvalho Chehab 425aee3deSMauro Carvalho Chehab Copyright (C) Manu Abraham (abraham.manu@gmail.com) 525aee3deSMauro Carvalho Chehab 625aee3deSMauro Carvalho Chehab This program is free software; you can redistribute it and/or modify 725aee3deSMauro Carvalho Chehab it under the terms of the GNU General Public License as published by 825aee3deSMauro Carvalho Chehab the Free Software Foundation; either version 2 of the License, or 925aee3deSMauro Carvalho Chehab (at your option) any later version. 1025aee3deSMauro Carvalho Chehab 1125aee3deSMauro Carvalho Chehab This program is distributed in the hope that it will be useful, 1225aee3deSMauro Carvalho Chehab but WITHOUT ANY WARRANTY; without even the implied warranty of 1325aee3deSMauro Carvalho Chehab MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1425aee3deSMauro Carvalho Chehab GNU General Public License for more details. 1525aee3deSMauro Carvalho Chehab 1625aee3deSMauro Carvalho Chehab You should have received a copy of the GNU General Public License 1725aee3deSMauro Carvalho Chehab along with this program; if not, write to the Free Software 1825aee3deSMauro Carvalho Chehab Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 1925aee3deSMauro Carvalho Chehab */ 2025aee3deSMauro Carvalho Chehab 2125aee3deSMauro Carvalho Chehab #include <linux/module.h> 2225aee3deSMauro Carvalho Chehab #include <linux/moduleparam.h> 2325aee3deSMauro Carvalho Chehab #include <linux/kernel.h> 2425aee3deSMauro Carvalho Chehab #include <linux/pci.h> 2525aee3deSMauro Carvalho Chehab #include <linux/slab.h> 2625aee3deSMauro Carvalho Chehab #include <asm/irq.h> 2725aee3deSMauro Carvalho Chehab #include <linux/interrupt.h> 2825aee3deSMauro Carvalho Chehab 2925aee3deSMauro Carvalho Chehab #include "dmxdev.h" 3025aee3deSMauro Carvalho Chehab #include "dvbdev.h" 3125aee3deSMauro Carvalho Chehab #include "dvb_demux.h" 3225aee3deSMauro Carvalho Chehab #include "dvb_frontend.h" 3325aee3deSMauro Carvalho Chehab #include "dvb_net.h" 3425aee3deSMauro Carvalho Chehab 3525aee3deSMauro Carvalho Chehab #include "mantis_common.h" 3625aee3deSMauro Carvalho Chehab #include "hopper_vp3028.h" 3725aee3deSMauro Carvalho Chehab #include "mantis_dma.h" 3825aee3deSMauro Carvalho Chehab #include "mantis_dvb.h" 3925aee3deSMauro Carvalho Chehab #include "mantis_uart.h" 4025aee3deSMauro Carvalho Chehab #include "mantis_ioc.h" 4125aee3deSMauro Carvalho Chehab #include "mantis_pci.h" 4225aee3deSMauro Carvalho Chehab #include "mantis_i2c.h" 4325aee3deSMauro Carvalho Chehab #include "mantis_reg.h" 4425aee3deSMauro Carvalho Chehab 4525aee3deSMauro Carvalho Chehab static unsigned int verbose; 4625aee3deSMauro Carvalho Chehab module_param(verbose, int, 0644); 4725aee3deSMauro Carvalho Chehab MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)"); 4825aee3deSMauro Carvalho Chehab 4925aee3deSMauro Carvalho Chehab #define DRIVER_NAME "Hopper" 5025aee3deSMauro Carvalho Chehab 5125aee3deSMauro Carvalho Chehab static char *label[10] = { 5225aee3deSMauro Carvalho Chehab "DMA", 5325aee3deSMauro Carvalho Chehab "IRQ-0", 5425aee3deSMauro Carvalho Chehab "IRQ-1", 5525aee3deSMauro Carvalho Chehab "OCERR", 5625aee3deSMauro Carvalho Chehab "PABRT", 5725aee3deSMauro Carvalho Chehab "RIPRR", 5825aee3deSMauro Carvalho Chehab "PPERR", 5925aee3deSMauro Carvalho Chehab "FTRGT", 6025aee3deSMauro Carvalho Chehab "RISCI", 6125aee3deSMauro Carvalho Chehab "RACK" 6225aee3deSMauro Carvalho Chehab }; 6325aee3deSMauro Carvalho Chehab 6425aee3deSMauro Carvalho Chehab static int devs; 6525aee3deSMauro Carvalho Chehab 6625aee3deSMauro Carvalho Chehab static irqreturn_t hopper_irq_handler(int irq, void *dev_id) 6725aee3deSMauro Carvalho Chehab { 6825aee3deSMauro Carvalho Chehab u32 stat = 0, mask = 0; 6925aee3deSMauro Carvalho Chehab u32 rst_stat = 0, rst_mask = 0; 7025aee3deSMauro Carvalho Chehab 7125aee3deSMauro Carvalho Chehab struct mantis_pci *mantis; 7225aee3deSMauro Carvalho Chehab struct mantis_ca *ca; 7325aee3deSMauro Carvalho Chehab 7425aee3deSMauro Carvalho Chehab mantis = (struct mantis_pci *) dev_id; 7525aee3deSMauro Carvalho Chehab if (unlikely(mantis == NULL)) { 7625aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); 7725aee3deSMauro Carvalho Chehab return IRQ_NONE; 7825aee3deSMauro Carvalho Chehab } 7925aee3deSMauro Carvalho Chehab ca = mantis->mantis_ca; 8025aee3deSMauro Carvalho Chehab 8125aee3deSMauro Carvalho Chehab stat = mmread(MANTIS_INT_STAT); 8225aee3deSMauro Carvalho Chehab mask = mmread(MANTIS_INT_MASK); 8325aee3deSMauro Carvalho Chehab if (!(stat & mask)) 8425aee3deSMauro Carvalho Chehab return IRQ_NONE; 8525aee3deSMauro Carvalho Chehab 8625aee3deSMauro Carvalho Chehab rst_mask = MANTIS_GPIF_WRACK | 8725aee3deSMauro Carvalho Chehab MANTIS_GPIF_OTHERR | 8825aee3deSMauro Carvalho Chehab MANTIS_SBUF_WSTO | 8925aee3deSMauro Carvalho Chehab MANTIS_GPIF_EXTIRQ; 9025aee3deSMauro Carvalho Chehab 9125aee3deSMauro Carvalho Chehab rst_stat = mmread(MANTIS_GPIF_STATUS); 9225aee3deSMauro Carvalho Chehab rst_stat &= rst_mask; 9325aee3deSMauro Carvalho Chehab mmwrite(rst_stat, MANTIS_GPIF_STATUS); 9425aee3deSMauro Carvalho Chehab 9525aee3deSMauro Carvalho Chehab mantis->mantis_int_stat = stat; 9625aee3deSMauro Carvalho Chehab mantis->mantis_int_mask = mask; 9725aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask); 9825aee3deSMauro Carvalho Chehab if (stat & MANTIS_INT_RISCEN) { 9925aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]); 10025aee3deSMauro Carvalho Chehab } 10125aee3deSMauro Carvalho Chehab if (stat & MANTIS_INT_IRQ0) { 10225aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]); 10325aee3deSMauro Carvalho Chehab mantis->gpif_status = rst_stat; 10425aee3deSMauro Carvalho Chehab wake_up(&ca->hif_write_wq); 10525aee3deSMauro Carvalho Chehab schedule_work(&ca->hif_evm_work); 10625aee3deSMauro Carvalho Chehab } 10725aee3deSMauro Carvalho Chehab if (stat & MANTIS_INT_IRQ1) { 10825aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); 10925aee3deSMauro Carvalho Chehab schedule_work(&mantis->uart_work); 11025aee3deSMauro Carvalho Chehab } 11125aee3deSMauro Carvalho Chehab if (stat & MANTIS_INT_OCERR) { 11225aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]); 11325aee3deSMauro Carvalho Chehab } 11425aee3deSMauro Carvalho Chehab if (stat & MANTIS_INT_PABORT) { 11525aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]); 11625aee3deSMauro Carvalho Chehab } 11725aee3deSMauro Carvalho Chehab if (stat & MANTIS_INT_RIPERR) { 11825aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]); 11925aee3deSMauro Carvalho Chehab } 12025aee3deSMauro Carvalho Chehab if (stat & MANTIS_INT_PPERR) { 12125aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]); 12225aee3deSMauro Carvalho Chehab } 12325aee3deSMauro Carvalho Chehab if (stat & MANTIS_INT_FTRGT) { 12425aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]); 12525aee3deSMauro Carvalho Chehab } 12625aee3deSMauro Carvalho Chehab if (stat & MANTIS_INT_RISCI) { 12725aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); 12825aee3deSMauro Carvalho Chehab mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; 12925aee3deSMauro Carvalho Chehab tasklet_schedule(&mantis->tasklet); 13025aee3deSMauro Carvalho Chehab } 13125aee3deSMauro Carvalho Chehab if (stat & MANTIS_INT_I2CDONE) { 13225aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); 13325aee3deSMauro Carvalho Chehab wake_up(&mantis->i2c_wq); 13425aee3deSMauro Carvalho Chehab } 13525aee3deSMauro Carvalho Chehab mmwrite(stat, MANTIS_INT_STAT); 13625aee3deSMauro Carvalho Chehab stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE | 13725aee3deSMauro Carvalho Chehab MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 | 13825aee3deSMauro Carvalho Chehab MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 | 13925aee3deSMauro Carvalho Chehab MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 | 14025aee3deSMauro Carvalho Chehab MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 | 14125aee3deSMauro Carvalho Chehab MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 | 14225aee3deSMauro Carvalho Chehab MANTIS_INT_IRQ0 | MANTIS_INT_OCERR | 14325aee3deSMauro Carvalho Chehab MANTIS_INT_PABORT | MANTIS_INT_RIPERR | 14425aee3deSMauro Carvalho Chehab MANTIS_INT_PPERR | MANTIS_INT_FTRGT | 14525aee3deSMauro Carvalho Chehab MANTIS_INT_RISCI); 14625aee3deSMauro Carvalho Chehab 14725aee3deSMauro Carvalho Chehab if (stat) 14825aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask); 14925aee3deSMauro Carvalho Chehab 15025aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 0, "\n"); 15125aee3deSMauro Carvalho Chehab return IRQ_HANDLED; 15225aee3deSMauro Carvalho Chehab } 15325aee3deSMauro Carvalho Chehab 1544c62e976SGreg Kroah-Hartman static int hopper_pci_probe(struct pci_dev *pdev, 1554c62e976SGreg Kroah-Hartman const struct pci_device_id *pci_id) 15625aee3deSMauro Carvalho Chehab { 15725aee3deSMauro Carvalho Chehab struct mantis_pci *mantis; 15825aee3deSMauro Carvalho Chehab struct mantis_hwconfig *config; 15925aee3deSMauro Carvalho Chehab int err = 0; 16025aee3deSMauro Carvalho Chehab 16125aee3deSMauro Carvalho Chehab mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); 16225aee3deSMauro Carvalho Chehab if (mantis == NULL) { 16325aee3deSMauro Carvalho Chehab printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); 16425aee3deSMauro Carvalho Chehab err = -ENOMEM; 16525aee3deSMauro Carvalho Chehab goto fail0; 16625aee3deSMauro Carvalho Chehab } 16725aee3deSMauro Carvalho Chehab 16825aee3deSMauro Carvalho Chehab mantis->num = devs; 16925aee3deSMauro Carvalho Chehab mantis->verbose = verbose; 17025aee3deSMauro Carvalho Chehab mantis->pdev = pdev; 17125aee3deSMauro Carvalho Chehab config = (struct mantis_hwconfig *) pci_id->driver_data; 17225aee3deSMauro Carvalho Chehab config->irq_handler = &hopper_irq_handler; 17325aee3deSMauro Carvalho Chehab mantis->hwconfig = config; 17425aee3deSMauro Carvalho Chehab 17525aee3deSMauro Carvalho Chehab err = mantis_pci_init(mantis); 17625aee3deSMauro Carvalho Chehab if (err) { 17725aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); 17825aee3deSMauro Carvalho Chehab goto fail1; 17925aee3deSMauro Carvalho Chehab } 18025aee3deSMauro Carvalho Chehab 18125aee3deSMauro Carvalho Chehab err = mantis_stream_control(mantis, STREAM_TO_HIF); 18225aee3deSMauro Carvalho Chehab if (err < 0) { 18325aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); 18425aee3deSMauro Carvalho Chehab goto fail1; 18525aee3deSMauro Carvalho Chehab } 18625aee3deSMauro Carvalho Chehab 18725aee3deSMauro Carvalho Chehab err = mantis_i2c_init(mantis); 18825aee3deSMauro Carvalho Chehab if (err < 0) { 18925aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); 19025aee3deSMauro Carvalho Chehab goto fail2; 19125aee3deSMauro Carvalho Chehab } 19225aee3deSMauro Carvalho Chehab 19325aee3deSMauro Carvalho Chehab err = mantis_get_mac(mantis); 19425aee3deSMauro Carvalho Chehab if (err < 0) { 19525aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); 19625aee3deSMauro Carvalho Chehab goto fail2; 19725aee3deSMauro Carvalho Chehab } 19825aee3deSMauro Carvalho Chehab 19925aee3deSMauro Carvalho Chehab err = mantis_dma_init(mantis); 20025aee3deSMauro Carvalho Chehab if (err < 0) { 20125aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); 20225aee3deSMauro Carvalho Chehab goto fail3; 20325aee3deSMauro Carvalho Chehab } 20425aee3deSMauro Carvalho Chehab 20525aee3deSMauro Carvalho Chehab err = mantis_dvb_init(mantis); 20625aee3deSMauro Carvalho Chehab if (err < 0) { 20725aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); 20825aee3deSMauro Carvalho Chehab goto fail4; 20925aee3deSMauro Carvalho Chehab } 21025aee3deSMauro Carvalho Chehab devs++; 21125aee3deSMauro Carvalho Chehab 21225aee3deSMauro Carvalho Chehab return err; 21325aee3deSMauro Carvalho Chehab 21425aee3deSMauro Carvalho Chehab fail4: 21525aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); 21625aee3deSMauro Carvalho Chehab mantis_dma_exit(mantis); 21725aee3deSMauro Carvalho Chehab 21825aee3deSMauro Carvalho Chehab fail3: 21925aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); 22025aee3deSMauro Carvalho Chehab mantis_i2c_exit(mantis); 22125aee3deSMauro Carvalho Chehab 22225aee3deSMauro Carvalho Chehab fail2: 22325aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); 22425aee3deSMauro Carvalho Chehab mantis_pci_exit(mantis); 22525aee3deSMauro Carvalho Chehab 22625aee3deSMauro Carvalho Chehab fail1: 22725aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); 22825aee3deSMauro Carvalho Chehab kfree(mantis); 22925aee3deSMauro Carvalho Chehab 23025aee3deSMauro Carvalho Chehab fail0: 23125aee3deSMauro Carvalho Chehab return err; 23225aee3deSMauro Carvalho Chehab } 23325aee3deSMauro Carvalho Chehab 2344c62e976SGreg Kroah-Hartman static void hopper_pci_remove(struct pci_dev *pdev) 23525aee3deSMauro Carvalho Chehab { 23625aee3deSMauro Carvalho Chehab struct mantis_pci *mantis = pci_get_drvdata(pdev); 23725aee3deSMauro Carvalho Chehab 23825aee3deSMauro Carvalho Chehab if (mantis) { 23925aee3deSMauro Carvalho Chehab mantis_dvb_exit(mantis); 24025aee3deSMauro Carvalho Chehab mantis_dma_exit(mantis); 24125aee3deSMauro Carvalho Chehab mantis_i2c_exit(mantis); 24225aee3deSMauro Carvalho Chehab mantis_pci_exit(mantis); 24325aee3deSMauro Carvalho Chehab kfree(mantis); 24425aee3deSMauro Carvalho Chehab } 24525aee3deSMauro Carvalho Chehab return; 24625aee3deSMauro Carvalho Chehab 24725aee3deSMauro Carvalho Chehab } 24825aee3deSMauro Carvalho Chehab 24925aee3deSMauro Carvalho Chehab static struct pci_device_id hopper_pci_table[] = { 25025aee3deSMauro Carvalho Chehab MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config), 25125aee3deSMauro Carvalho Chehab { } 25225aee3deSMauro Carvalho Chehab }; 25325aee3deSMauro Carvalho Chehab 25425aee3deSMauro Carvalho Chehab MODULE_DEVICE_TABLE(pci, hopper_pci_table); 25525aee3deSMauro Carvalho Chehab 25625aee3deSMauro Carvalho Chehab static struct pci_driver hopper_pci_driver = { 25725aee3deSMauro Carvalho Chehab .name = DRIVER_NAME, 25825aee3deSMauro Carvalho Chehab .id_table = hopper_pci_table, 25925aee3deSMauro Carvalho Chehab .probe = hopper_pci_probe, 26025aee3deSMauro Carvalho Chehab .remove = hopper_pci_remove, 26125aee3deSMauro Carvalho Chehab }; 26225aee3deSMauro Carvalho Chehab 263*ecef5cc3SLibo Chen module_pci_driver(hopper_pci_driver); 26425aee3deSMauro Carvalho Chehab 26525aee3deSMauro Carvalho Chehab MODULE_DESCRIPTION("HOPPER driver"); 26625aee3deSMauro Carvalho Chehab MODULE_AUTHOR("Manu Abraham"); 26725aee3deSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 268