xref: /openbmc/linux/drivers/media/pci/mantis/hopper_cards.c (revision c95baf12f5077419db01313ab61c2aac007d40cd)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
225aee3deSMauro Carvalho Chehab /*
325aee3deSMauro Carvalho Chehab 	Hopper PCI bridge driver
425aee3deSMauro Carvalho Chehab 
525aee3deSMauro Carvalho Chehab 	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
625aee3deSMauro Carvalho Chehab 
725aee3deSMauro Carvalho Chehab */
825aee3deSMauro Carvalho Chehab 
925aee3deSMauro Carvalho Chehab #include <linux/module.h>
1025aee3deSMauro Carvalho Chehab #include <linux/moduleparam.h>
1125aee3deSMauro Carvalho Chehab #include <linux/kernel.h>
1225aee3deSMauro Carvalho Chehab #include <linux/pci.h>
1325aee3deSMauro Carvalho Chehab #include <linux/slab.h>
1425aee3deSMauro Carvalho Chehab #include <asm/irq.h>
1525aee3deSMauro Carvalho Chehab #include <linux/interrupt.h>
1625aee3deSMauro Carvalho Chehab 
17fada1935SMauro Carvalho Chehab #include <media/dmxdev.h>
18fada1935SMauro Carvalho Chehab #include <media/dvbdev.h>
19fada1935SMauro Carvalho Chehab #include <media/dvb_demux.h>
20fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
21fada1935SMauro Carvalho Chehab #include <media/dvb_net.h>
2225aee3deSMauro Carvalho Chehab 
2325aee3deSMauro Carvalho Chehab #include "mantis_common.h"
2425aee3deSMauro Carvalho Chehab #include "hopper_vp3028.h"
2525aee3deSMauro Carvalho Chehab #include "mantis_dma.h"
2625aee3deSMauro Carvalho Chehab #include "mantis_dvb.h"
2725aee3deSMauro Carvalho Chehab #include "mantis_uart.h"
2825aee3deSMauro Carvalho Chehab #include "mantis_ioc.h"
2925aee3deSMauro Carvalho Chehab #include "mantis_pci.h"
3025aee3deSMauro Carvalho Chehab #include "mantis_i2c.h"
3125aee3deSMauro Carvalho Chehab #include "mantis_reg.h"
3225aee3deSMauro Carvalho Chehab 
3325aee3deSMauro Carvalho Chehab static unsigned int verbose;
3425aee3deSMauro Carvalho Chehab module_param(verbose, int, 0644);
3525aee3deSMauro Carvalho Chehab MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)");
3625aee3deSMauro Carvalho Chehab 
3725aee3deSMauro Carvalho Chehab #define DRIVER_NAME	"Hopper"
3825aee3deSMauro Carvalho Chehab 
3925aee3deSMauro Carvalho Chehab static char *label[10] = {
4025aee3deSMauro Carvalho Chehab 	"DMA",
4125aee3deSMauro Carvalho Chehab 	"IRQ-0",
4225aee3deSMauro Carvalho Chehab 	"IRQ-1",
4325aee3deSMauro Carvalho Chehab 	"OCERR",
4425aee3deSMauro Carvalho Chehab 	"PABRT",
4525aee3deSMauro Carvalho Chehab 	"RIPRR",
4625aee3deSMauro Carvalho Chehab 	"PPERR",
4725aee3deSMauro Carvalho Chehab 	"FTRGT",
4825aee3deSMauro Carvalho Chehab 	"RISCI",
4925aee3deSMauro Carvalho Chehab 	"RACK"
5025aee3deSMauro Carvalho Chehab };
5125aee3deSMauro Carvalho Chehab 
5225aee3deSMauro Carvalho Chehab static int devs;
5325aee3deSMauro Carvalho Chehab 
hopper_irq_handler(int irq,void * dev_id)5425aee3deSMauro Carvalho Chehab static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
5525aee3deSMauro Carvalho Chehab {
5625aee3deSMauro Carvalho Chehab 	u32 stat = 0, mask = 0;
5725aee3deSMauro Carvalho Chehab 	u32 rst_stat = 0, rst_mask = 0;
5825aee3deSMauro Carvalho Chehab 
5925aee3deSMauro Carvalho Chehab 	struct mantis_pci *mantis;
6025aee3deSMauro Carvalho Chehab 	struct mantis_ca *ca;
6125aee3deSMauro Carvalho Chehab 
6225aee3deSMauro Carvalho Chehab 	mantis = (struct mantis_pci *) dev_id;
63*61b8584aSHans Verkuil 	if (unlikely(!mantis))
6425aee3deSMauro Carvalho Chehab 		return IRQ_NONE;
6525aee3deSMauro Carvalho Chehab 	ca = mantis->mantis_ca;
6625aee3deSMauro Carvalho Chehab 
6725aee3deSMauro Carvalho Chehab 	stat = mmread(MANTIS_INT_STAT);
6825aee3deSMauro Carvalho Chehab 	mask = mmread(MANTIS_INT_MASK);
6925aee3deSMauro Carvalho Chehab 	if (!(stat & mask))
7025aee3deSMauro Carvalho Chehab 		return IRQ_NONE;
7125aee3deSMauro Carvalho Chehab 
7225aee3deSMauro Carvalho Chehab 	rst_mask  = MANTIS_GPIF_WRACK  |
7325aee3deSMauro Carvalho Chehab 		    MANTIS_GPIF_OTHERR |
7425aee3deSMauro Carvalho Chehab 		    MANTIS_SBUF_WSTO   |
7525aee3deSMauro Carvalho Chehab 		    MANTIS_GPIF_EXTIRQ;
7625aee3deSMauro Carvalho Chehab 
7725aee3deSMauro Carvalho Chehab 	rst_stat  = mmread(MANTIS_GPIF_STATUS);
7825aee3deSMauro Carvalho Chehab 	rst_stat &= rst_mask;
7925aee3deSMauro Carvalho Chehab 	mmwrite(rst_stat, MANTIS_GPIF_STATUS);
8025aee3deSMauro Carvalho Chehab 
8125aee3deSMauro Carvalho Chehab 	mantis->mantis_int_stat = stat;
8225aee3deSMauro Carvalho Chehab 	mantis->mantis_int_mask = mask;
8325aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
8425aee3deSMauro Carvalho Chehab 	if (stat & MANTIS_INT_RISCEN) {
8525aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
8625aee3deSMauro Carvalho Chehab 	}
8725aee3deSMauro Carvalho Chehab 	if (stat & MANTIS_INT_IRQ0) {
8825aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
8925aee3deSMauro Carvalho Chehab 		mantis->gpif_status = rst_stat;
9025aee3deSMauro Carvalho Chehab 		wake_up(&ca->hif_write_wq);
9125aee3deSMauro Carvalho Chehab 		schedule_work(&ca->hif_evm_work);
9225aee3deSMauro Carvalho Chehab 	}
9325aee3deSMauro Carvalho Chehab 	if (stat & MANTIS_INT_IRQ1) {
9425aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
95a96762daSJan Klötzke 		spin_lock(&mantis->intmask_lock);
969d605e63SMauro Carvalho Chehab 		mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ1,
979d605e63SMauro Carvalho Chehab 			MANTIS_INT_MASK);
98a96762daSJan Klötzke 		spin_unlock(&mantis->intmask_lock);
9925aee3deSMauro Carvalho Chehab 		schedule_work(&mantis->uart_work);
10025aee3deSMauro Carvalho Chehab 	}
10125aee3deSMauro Carvalho Chehab 	if (stat & MANTIS_INT_OCERR) {
10225aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
10325aee3deSMauro Carvalho Chehab 	}
10425aee3deSMauro Carvalho Chehab 	if (stat & MANTIS_INT_PABORT) {
10525aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
10625aee3deSMauro Carvalho Chehab 	}
10725aee3deSMauro Carvalho Chehab 	if (stat & MANTIS_INT_RIPERR) {
10825aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
10925aee3deSMauro Carvalho Chehab 	}
11025aee3deSMauro Carvalho Chehab 	if (stat & MANTIS_INT_PPERR) {
11125aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
11225aee3deSMauro Carvalho Chehab 	}
11325aee3deSMauro Carvalho Chehab 	if (stat & MANTIS_INT_FTRGT) {
11425aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
11525aee3deSMauro Carvalho Chehab 	}
11625aee3deSMauro Carvalho Chehab 	if (stat & MANTIS_INT_RISCI) {
11725aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
11825aee3deSMauro Carvalho Chehab 		mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
11925aee3deSMauro Carvalho Chehab 		tasklet_schedule(&mantis->tasklet);
12025aee3deSMauro Carvalho Chehab 	}
12125aee3deSMauro Carvalho Chehab 	if (stat & MANTIS_INT_I2CDONE) {
12225aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
12325aee3deSMauro Carvalho Chehab 		wake_up(&mantis->i2c_wq);
12425aee3deSMauro Carvalho Chehab 	}
12525aee3deSMauro Carvalho Chehab 	mmwrite(stat, MANTIS_INT_STAT);
12625aee3deSMauro Carvalho Chehab 	stat &= ~(MANTIS_INT_RISCEN   | MANTIS_INT_I2CDONE |
12725aee3deSMauro Carvalho Chehab 		  MANTIS_INT_I2CRACK  | MANTIS_INT_PCMCIA7 |
12825aee3deSMauro Carvalho Chehab 		  MANTIS_INT_PCMCIA6  | MANTIS_INT_PCMCIA5 |
12925aee3deSMauro Carvalho Chehab 		  MANTIS_INT_PCMCIA4  | MANTIS_INT_PCMCIA3 |
13025aee3deSMauro Carvalho Chehab 		  MANTIS_INT_PCMCIA2  | MANTIS_INT_PCMCIA1 |
13125aee3deSMauro Carvalho Chehab 		  MANTIS_INT_PCMCIA0  | MANTIS_INT_IRQ1	   |
13225aee3deSMauro Carvalho Chehab 		  MANTIS_INT_IRQ0     | MANTIS_INT_OCERR   |
13325aee3deSMauro Carvalho Chehab 		  MANTIS_INT_PABORT   | MANTIS_INT_RIPERR  |
13425aee3deSMauro Carvalho Chehab 		  MANTIS_INT_PPERR    | MANTIS_INT_FTRGT   |
13525aee3deSMauro Carvalho Chehab 		  MANTIS_INT_RISCI);
13625aee3deSMauro Carvalho Chehab 
13725aee3deSMauro Carvalho Chehab 	if (stat)
13825aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
13925aee3deSMauro Carvalho Chehab 
14025aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_DEBUG, 0, "\n");
14125aee3deSMauro Carvalho Chehab 	return IRQ_HANDLED;
14225aee3deSMauro Carvalho Chehab }
14325aee3deSMauro Carvalho Chehab 
hopper_pci_probe(struct pci_dev * pdev,const struct pci_device_id * pci_id)1444c62e976SGreg Kroah-Hartman static int hopper_pci_probe(struct pci_dev *pdev,
1454c62e976SGreg Kroah-Hartman 			    const struct pci_device_id *pci_id)
14625aee3deSMauro Carvalho Chehab {
147a96762daSJan Klötzke 	struct mantis_pci_drvdata *drvdata;
14825aee3deSMauro Carvalho Chehab 	struct mantis_pci *mantis;
14925aee3deSMauro Carvalho Chehab 	struct mantis_hwconfig *config;
150d303b7c5SMarkus Elfring 	int err;
15125aee3deSMauro Carvalho Chehab 
1522d3da59fSMarkus Elfring 	mantis = kzalloc(sizeof(*mantis), GFP_KERNEL);
153af28c996SMarkus Elfring 	if (!mantis) {
15425aee3deSMauro Carvalho Chehab 		err = -ENOMEM;
15525aee3deSMauro Carvalho Chehab 		goto fail0;
15625aee3deSMauro Carvalho Chehab 	}
15725aee3deSMauro Carvalho Chehab 
1589d605e63SMauro Carvalho Chehab 	drvdata			= (void *)pci_id->driver_data;
15925aee3deSMauro Carvalho Chehab 	mantis->num		= devs;
16025aee3deSMauro Carvalho Chehab 	mantis->verbose		= verbose;
16125aee3deSMauro Carvalho Chehab 	mantis->pdev		= pdev;
162a96762daSJan Klötzke 	config			= drvdata->hwconfig;
16325aee3deSMauro Carvalho Chehab 	config->irq_handler	= &hopper_irq_handler;
16425aee3deSMauro Carvalho Chehab 	mantis->hwconfig	= config;
165a96762daSJan Klötzke 	mantis->rc_map_name	= drvdata->rc_map_name;
166a96762daSJan Klötzke 
167a96762daSJan Klötzke 	spin_lock_init(&mantis->intmask_lock);
16825aee3deSMauro Carvalho Chehab 
16925aee3deSMauro Carvalho Chehab 	err = mantis_pci_init(mantis);
17025aee3deSMauro Carvalho Chehab 	if (err) {
17125aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
17225aee3deSMauro Carvalho Chehab 		goto fail1;
17325aee3deSMauro Carvalho Chehab 	}
17425aee3deSMauro Carvalho Chehab 
17525aee3deSMauro Carvalho Chehab 	err = mantis_stream_control(mantis, STREAM_TO_HIF);
17625aee3deSMauro Carvalho Chehab 	if (err < 0) {
17725aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
17825aee3deSMauro Carvalho Chehab 		goto fail1;
17925aee3deSMauro Carvalho Chehab 	}
18025aee3deSMauro Carvalho Chehab 
18125aee3deSMauro Carvalho Chehab 	err = mantis_i2c_init(mantis);
18225aee3deSMauro Carvalho Chehab 	if (err < 0) {
18325aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
18425aee3deSMauro Carvalho Chehab 		goto fail2;
18525aee3deSMauro Carvalho Chehab 	}
18625aee3deSMauro Carvalho Chehab 
18725aee3deSMauro Carvalho Chehab 	err = mantis_get_mac(mantis);
18825aee3deSMauro Carvalho Chehab 	if (err < 0) {
18925aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
19025aee3deSMauro Carvalho Chehab 		goto fail2;
19125aee3deSMauro Carvalho Chehab 	}
19225aee3deSMauro Carvalho Chehab 
19325aee3deSMauro Carvalho Chehab 	err = mantis_dma_init(mantis);
19425aee3deSMauro Carvalho Chehab 	if (err < 0) {
19525aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
19625aee3deSMauro Carvalho Chehab 		goto fail3;
19725aee3deSMauro Carvalho Chehab 	}
19825aee3deSMauro Carvalho Chehab 
19925aee3deSMauro Carvalho Chehab 	err = mantis_dvb_init(mantis);
20025aee3deSMauro Carvalho Chehab 	if (err < 0) {
20125aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
20225aee3deSMauro Carvalho Chehab 		goto fail4;
20325aee3deSMauro Carvalho Chehab 	}
20425aee3deSMauro Carvalho Chehab 	devs++;
20525aee3deSMauro Carvalho Chehab 
20625aee3deSMauro Carvalho Chehab 	return err;
20725aee3deSMauro Carvalho Chehab 
20825aee3deSMauro Carvalho Chehab fail4:
20925aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
21025aee3deSMauro Carvalho Chehab 	mantis_dma_exit(mantis);
21125aee3deSMauro Carvalho Chehab 
21225aee3deSMauro Carvalho Chehab fail3:
21325aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
21425aee3deSMauro Carvalho Chehab 	mantis_i2c_exit(mantis);
21525aee3deSMauro Carvalho Chehab 
21625aee3deSMauro Carvalho Chehab fail2:
21725aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
21825aee3deSMauro Carvalho Chehab 	mantis_pci_exit(mantis);
21925aee3deSMauro Carvalho Chehab 
22025aee3deSMauro Carvalho Chehab fail1:
22125aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
22225aee3deSMauro Carvalho Chehab 	kfree(mantis);
22325aee3deSMauro Carvalho Chehab 
22425aee3deSMauro Carvalho Chehab fail0:
22525aee3deSMauro Carvalho Chehab 	return err;
22625aee3deSMauro Carvalho Chehab }
22725aee3deSMauro Carvalho Chehab 
hopper_pci_remove(struct pci_dev * pdev)2284c62e976SGreg Kroah-Hartman static void hopper_pci_remove(struct pci_dev *pdev)
22925aee3deSMauro Carvalho Chehab {
23025aee3deSMauro Carvalho Chehab 	struct mantis_pci *mantis = pci_get_drvdata(pdev);
23125aee3deSMauro Carvalho Chehab 
23225aee3deSMauro Carvalho Chehab 	if (mantis) {
23325aee3deSMauro Carvalho Chehab 		mantis_dvb_exit(mantis);
23425aee3deSMauro Carvalho Chehab 		mantis_dma_exit(mantis);
23525aee3deSMauro Carvalho Chehab 		mantis_i2c_exit(mantis);
23625aee3deSMauro Carvalho Chehab 		mantis_pci_exit(mantis);
23725aee3deSMauro Carvalho Chehab 		kfree(mantis);
23825aee3deSMauro Carvalho Chehab 	}
23925aee3deSMauro Carvalho Chehab 	return;
24025aee3deSMauro Carvalho Chehab 
24125aee3deSMauro Carvalho Chehab }
24225aee3deSMauro Carvalho Chehab 
2432b9e300fSArvind Yadav static const struct pci_device_id hopper_pci_table[] = {
244a96762daSJan Klötzke 	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config,
245a96762daSJan Klötzke 		   NULL),
24625aee3deSMauro Carvalho Chehab 	{ }
24725aee3deSMauro Carvalho Chehab };
24825aee3deSMauro Carvalho Chehab 
24925aee3deSMauro Carvalho Chehab MODULE_DEVICE_TABLE(pci, hopper_pci_table);
25025aee3deSMauro Carvalho Chehab 
25125aee3deSMauro Carvalho Chehab static struct pci_driver hopper_pci_driver = {
25225aee3deSMauro Carvalho Chehab 	.name		= DRIVER_NAME,
25325aee3deSMauro Carvalho Chehab 	.id_table	= hopper_pci_table,
25425aee3deSMauro Carvalho Chehab 	.probe		= hopper_pci_probe,
25525aee3deSMauro Carvalho Chehab 	.remove		= hopper_pci_remove,
25625aee3deSMauro Carvalho Chehab };
25725aee3deSMauro Carvalho Chehab 
258ecef5cc3SLibo Chen module_pci_driver(hopper_pci_driver);
25925aee3deSMauro Carvalho Chehab 
26025aee3deSMauro Carvalho Chehab MODULE_DESCRIPTION("HOPPER driver");
26125aee3deSMauro Carvalho Chehab MODULE_AUTHOR("Manu Abraham");
26225aee3deSMauro Carvalho Chehab MODULE_LICENSE("GPL");
263