174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
225aee3deSMauro Carvalho Chehab /*
325aee3deSMauro Carvalho Chehab 	Mantis PCI bridge driver
425aee3deSMauro Carvalho Chehab 	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
525aee3deSMauro Carvalho Chehab 
625aee3deSMauro Carvalho Chehab */
725aee3deSMauro Carvalho Chehab 
825aee3deSMauro Carvalho Chehab #include <linux/kernel.h>
925aee3deSMauro Carvalho Chehab #include <linux/bitops.h>
1025aee3deSMauro Carvalho Chehab 
1125aee3deSMauro Carvalho Chehab #include <linux/signal.h>
1225aee3deSMauro Carvalho Chehab #include <linux/sched.h>
1325aee3deSMauro Carvalho Chehab #include <linux/interrupt.h>
1425aee3deSMauro Carvalho Chehab #include <linux/pci.h>
1525aee3deSMauro Carvalho Chehab #include <linux/i2c.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 "mantis_dma.h"
2525aee3deSMauro Carvalho Chehab #include "mantis_ca.h"
2625aee3deSMauro Carvalho Chehab #include "mantis_ioc.h"
2725aee3deSMauro Carvalho Chehab #include "mantis_dvb.h"
2825aee3deSMauro Carvalho Chehab 
2925aee3deSMauro Carvalho Chehab DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
3025aee3deSMauro Carvalho Chehab 
mantis_frontend_power(struct mantis_pci * mantis,enum mantis_power power)3125aee3deSMauro Carvalho Chehab int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)
3225aee3deSMauro Carvalho Chehab {
3325aee3deSMauro Carvalho Chehab 	struct mantis_hwconfig *config = mantis->hwconfig;
3425aee3deSMauro Carvalho Chehab 
3525aee3deSMauro Carvalho Chehab 	switch (power) {
3625aee3deSMauro Carvalho Chehab 	case POWER_ON:
3725aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 1, "Power ON");
3825aee3deSMauro Carvalho Chehab 		mantis_gpio_set_bits(mantis, config->power, POWER_ON);
3925aee3deSMauro Carvalho Chehab 		msleep(100);
4025aee3deSMauro Carvalho Chehab 		mantis_gpio_set_bits(mantis, config->power, POWER_ON);
4125aee3deSMauro Carvalho Chehab 		msleep(100);
4225aee3deSMauro Carvalho Chehab 		break;
4325aee3deSMauro Carvalho Chehab 
4425aee3deSMauro Carvalho Chehab 	case POWER_OFF:
4525aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 1, "Power OFF");
4625aee3deSMauro Carvalho Chehab 		mantis_gpio_set_bits(mantis, config->power, POWER_OFF);
4725aee3deSMauro Carvalho Chehab 		msleep(100);
4825aee3deSMauro Carvalho Chehab 		break;
4925aee3deSMauro Carvalho Chehab 
5025aee3deSMauro Carvalho Chehab 	default:
5125aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power);
5225aee3deSMauro Carvalho Chehab 		return -1;
5325aee3deSMauro Carvalho Chehab 	}
5425aee3deSMauro Carvalho Chehab 
5525aee3deSMauro Carvalho Chehab 	return 0;
5625aee3deSMauro Carvalho Chehab }
5725aee3deSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(mantis_frontend_power);
5825aee3deSMauro Carvalho Chehab 
mantis_frontend_soft_reset(struct mantis_pci * mantis)5925aee3deSMauro Carvalho Chehab void mantis_frontend_soft_reset(struct mantis_pci *mantis)
6025aee3deSMauro Carvalho Chehab {
6125aee3deSMauro Carvalho Chehab 	struct mantis_hwconfig *config = mantis->hwconfig;
6225aee3deSMauro Carvalho Chehab 
6325aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_DEBUG, 1, "Frontend RESET");
6425aee3deSMauro Carvalho Chehab 	mantis_gpio_set_bits(mantis, config->reset, 0);
6525aee3deSMauro Carvalho Chehab 	msleep(100);
6625aee3deSMauro Carvalho Chehab 	mantis_gpio_set_bits(mantis, config->reset, 0);
6725aee3deSMauro Carvalho Chehab 	msleep(100);
6825aee3deSMauro Carvalho Chehab 	mantis_gpio_set_bits(mantis, config->reset, 1);
6925aee3deSMauro Carvalho Chehab 	msleep(100);
7025aee3deSMauro Carvalho Chehab 	mantis_gpio_set_bits(mantis, config->reset, 1);
7125aee3deSMauro Carvalho Chehab 	msleep(100);
7225aee3deSMauro Carvalho Chehab 
7325aee3deSMauro Carvalho Chehab 	return;
7425aee3deSMauro Carvalho Chehab }
7525aee3deSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset);
7625aee3deSMauro Carvalho Chehab 
mantis_frontend_shutdown(struct mantis_pci * mantis)7725aee3deSMauro Carvalho Chehab static int mantis_frontend_shutdown(struct mantis_pci *mantis)
7825aee3deSMauro Carvalho Chehab {
7925aee3deSMauro Carvalho Chehab 	int err;
8025aee3deSMauro Carvalho Chehab 
8125aee3deSMauro Carvalho Chehab 	mantis_frontend_soft_reset(mantis);
8225aee3deSMauro Carvalho Chehab 	err = mantis_frontend_power(mantis, POWER_OFF);
8325aee3deSMauro Carvalho Chehab 	if (err != 0) {
8425aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err);
8525aee3deSMauro Carvalho Chehab 		return 1;
8625aee3deSMauro Carvalho Chehab 	}
8725aee3deSMauro Carvalho Chehab 
8825aee3deSMauro Carvalho Chehab 	return 0;
8925aee3deSMauro Carvalho Chehab }
9025aee3deSMauro Carvalho Chehab 
mantis_dvb_start_feed(struct dvb_demux_feed * dvbdmxfeed)9125aee3deSMauro Carvalho Chehab static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
9225aee3deSMauro Carvalho Chehab {
9325aee3deSMauro Carvalho Chehab 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
9425aee3deSMauro Carvalho Chehab 	struct mantis_pci *mantis = dvbdmx->priv;
9525aee3deSMauro Carvalho Chehab 
9625aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed");
9725aee3deSMauro Carvalho Chehab 	if (!dvbdmx->dmx.frontend) {
9825aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 1, "no frontend ?");
9925aee3deSMauro Carvalho Chehab 		return -EINVAL;
10025aee3deSMauro Carvalho Chehab 	}
10125aee3deSMauro Carvalho Chehab 
10225aee3deSMauro Carvalho Chehab 	mantis->feeds++;
10325aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d",	mantis->feeds);
10425aee3deSMauro Carvalho Chehab 
10525aee3deSMauro Carvalho Chehab 	if (mantis->feeds == 1)	 {
10625aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
10725aee3deSMauro Carvalho Chehab 		mantis_dma_start(mantis);
10825aee3deSMauro Carvalho Chehab 		tasklet_enable(&mantis->tasklet);
10925aee3deSMauro Carvalho Chehab 	}
11025aee3deSMauro Carvalho Chehab 
11125aee3deSMauro Carvalho Chehab 	return mantis->feeds;
11225aee3deSMauro Carvalho Chehab }
11325aee3deSMauro Carvalho Chehab 
mantis_dvb_stop_feed(struct dvb_demux_feed * dvbdmxfeed)11425aee3deSMauro Carvalho Chehab static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
11525aee3deSMauro Carvalho Chehab {
11625aee3deSMauro Carvalho Chehab 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
11725aee3deSMauro Carvalho Chehab 	struct mantis_pci *mantis = dvbdmx->priv;
11825aee3deSMauro Carvalho Chehab 
11925aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed");
12025aee3deSMauro Carvalho Chehab 	if (!dvbdmx->dmx.frontend) {
12125aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 1, "no frontend ?");
12225aee3deSMauro Carvalho Chehab 		return -EINVAL;
12325aee3deSMauro Carvalho Chehab 	}
12425aee3deSMauro Carvalho Chehab 
12525aee3deSMauro Carvalho Chehab 	mantis->feeds--;
12625aee3deSMauro Carvalho Chehab 	if (mantis->feeds == 0) {
12725aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
12825aee3deSMauro Carvalho Chehab 		tasklet_disable(&mantis->tasklet);
12925aee3deSMauro Carvalho Chehab 		mantis_dma_stop(mantis);
13025aee3deSMauro Carvalho Chehab 	}
13125aee3deSMauro Carvalho Chehab 
13225aee3deSMauro Carvalho Chehab 	return 0;
13325aee3deSMauro Carvalho Chehab }
13425aee3deSMauro Carvalho Chehab 
mantis_dvb_init(struct mantis_pci * mantis)1354c62e976SGreg Kroah-Hartman int mantis_dvb_init(struct mantis_pci *mantis)
13625aee3deSMauro Carvalho Chehab {
13725aee3deSMauro Carvalho Chehab 	struct mantis_hwconfig *config = mantis->hwconfig;
13877d30eabSColin Ian King 	int result;
13925aee3deSMauro Carvalho Chehab 
14025aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter");
14125aee3deSMauro Carvalho Chehab 
14225aee3deSMauro Carvalho Chehab 	result = dvb_register_adapter(&mantis->dvb_adapter,
14325aee3deSMauro Carvalho Chehab 				      "Mantis DVB adapter",
14425aee3deSMauro Carvalho Chehab 				      THIS_MODULE,
14525aee3deSMauro Carvalho Chehab 				      &mantis->pdev->dev,
14625aee3deSMauro Carvalho Chehab 				      adapter_nr);
14725aee3deSMauro Carvalho Chehab 
14825aee3deSMauro Carvalho Chehab 	if (result < 0) {
14925aee3deSMauro Carvalho Chehab 
15025aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_ERROR, 1, "Error registering adapter");
15125aee3deSMauro Carvalho Chehab 		return -ENODEV;
15225aee3deSMauro Carvalho Chehab 	}
15325aee3deSMauro Carvalho Chehab 
15425aee3deSMauro Carvalho Chehab 	mantis->dvb_adapter.priv	= mantis;
15525aee3deSMauro Carvalho Chehab 	mantis->demux.dmx.capabilities	= DMX_TS_FILTERING	|
15625aee3deSMauro Carvalho Chehab 					 DMX_SECTION_FILTERING	|
15725aee3deSMauro Carvalho Chehab 					 DMX_MEMORY_BASED_FILTERING;
15825aee3deSMauro Carvalho Chehab 
15925aee3deSMauro Carvalho Chehab 	mantis->demux.priv		= mantis;
16025aee3deSMauro Carvalho Chehab 	mantis->demux.filternum		= 256;
16125aee3deSMauro Carvalho Chehab 	mantis->demux.feednum		= 256;
16225aee3deSMauro Carvalho Chehab 	mantis->demux.start_feed	= mantis_dvb_start_feed;
16325aee3deSMauro Carvalho Chehab 	mantis->demux.stop_feed		= mantis_dvb_stop_feed;
16425aee3deSMauro Carvalho Chehab 	mantis->demux.write_to_decoder	= NULL;
16525aee3deSMauro Carvalho Chehab 
16625aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init");
16725aee3deSMauro Carvalho Chehab 	result = dvb_dmx_init(&mantis->demux);
16825aee3deSMauro Carvalho Chehab 	if (result < 0) {
16925aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
17025aee3deSMauro Carvalho Chehab 
17125aee3deSMauro Carvalho Chehab 		goto err0;
17225aee3deSMauro Carvalho Chehab 	}
17325aee3deSMauro Carvalho Chehab 
17425aee3deSMauro Carvalho Chehab 	mantis->dmxdev.filternum	= 256;
17525aee3deSMauro Carvalho Chehab 	mantis->dmxdev.demux		= &mantis->demux.dmx;
17625aee3deSMauro Carvalho Chehab 	mantis->dmxdev.capabilities	= 0;
17725aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init");
17825aee3deSMauro Carvalho Chehab 
17925aee3deSMauro Carvalho Chehab 	result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter);
18025aee3deSMauro Carvalho Chehab 	if (result < 0) {
18125aee3deSMauro Carvalho Chehab 
18225aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result);
18325aee3deSMauro Carvalho Chehab 		goto err1;
18425aee3deSMauro Carvalho Chehab 	}
18525aee3deSMauro Carvalho Chehab 
18625aee3deSMauro Carvalho Chehab 	mantis->fe_hw.source		= DMX_FRONTEND_0;
18725aee3deSMauro Carvalho Chehab 	result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw);
18825aee3deSMauro Carvalho Chehab 	if (result < 0) {
18925aee3deSMauro Carvalho Chehab 
19025aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
19125aee3deSMauro Carvalho Chehab 		goto err2;
19225aee3deSMauro Carvalho Chehab 	}
19325aee3deSMauro Carvalho Chehab 
19425aee3deSMauro Carvalho Chehab 	mantis->fe_mem.source		= DMX_MEMORY_FE;
19525aee3deSMauro Carvalho Chehab 	result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem);
19625aee3deSMauro Carvalho Chehab 	if (result < 0) {
19725aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
19825aee3deSMauro Carvalho Chehab 		goto err3;
19925aee3deSMauro Carvalho Chehab 	}
20025aee3deSMauro Carvalho Chehab 
20125aee3deSMauro Carvalho Chehab 	result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw);
20225aee3deSMauro Carvalho Chehab 	if (result < 0) {
20325aee3deSMauro Carvalho Chehab 		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
20425aee3deSMauro Carvalho Chehab 		goto err4;
20525aee3deSMauro Carvalho Chehab 	}
20625aee3deSMauro Carvalho Chehab 
20725aee3deSMauro Carvalho Chehab 	dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
2084cf709c9SAllen Pais 	tasklet_setup(&mantis->tasklet, mantis_dma_xfer);
20925aee3deSMauro Carvalho Chehab 	tasklet_disable(&mantis->tasklet);
21025aee3deSMauro Carvalho Chehab 	if (mantis->hwconfig) {
21125aee3deSMauro Carvalho Chehab 		result = config->frontend_init(mantis, mantis->fe);
21225aee3deSMauro Carvalho Chehab 		if (result < 0) {
21325aee3deSMauro Carvalho Chehab 			dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!");
21425aee3deSMauro Carvalho Chehab 			goto err5;
21525aee3deSMauro Carvalho Chehab 		} else {
21625aee3deSMauro Carvalho Chehab 			if (mantis->fe == NULL) {
21779a2eda8SDan Carpenter 				result = -ENOMEM;
21825aee3deSMauro Carvalho Chehab 				dprintk(MANTIS_ERROR, 1, "FE <NULL>");
21925aee3deSMauro Carvalho Chehab 				goto err5;
22025aee3deSMauro Carvalho Chehab 			}
22179a2eda8SDan Carpenter 			result = dvb_register_frontend(&mantis->dvb_adapter, mantis->fe);
22279a2eda8SDan Carpenter 			if (result) {
22325aee3deSMauro Carvalho Chehab 				dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed");
22425aee3deSMauro Carvalho Chehab 
22525aee3deSMauro Carvalho Chehab 				if (mantis->fe->ops.release)
22625aee3deSMauro Carvalho Chehab 					mantis->fe->ops.release(mantis->fe);
22725aee3deSMauro Carvalho Chehab 
22825aee3deSMauro Carvalho Chehab 				mantis->fe = NULL;
22925aee3deSMauro Carvalho Chehab 				goto err5;
23025aee3deSMauro Carvalho Chehab 			}
23125aee3deSMauro Carvalho Chehab 		}
23225aee3deSMauro Carvalho Chehab 	}
23325aee3deSMauro Carvalho Chehab 
23425aee3deSMauro Carvalho Chehab 	return 0;
23525aee3deSMauro Carvalho Chehab 
23625aee3deSMauro Carvalho Chehab 	/* Error conditions ..	*/
23725aee3deSMauro Carvalho Chehab err5:
23825aee3deSMauro Carvalho Chehab 	tasklet_kill(&mantis->tasklet);
23925aee3deSMauro Carvalho Chehab 	dvb_net_release(&mantis->dvbnet);
24025aee3deSMauro Carvalho Chehab 	if (mantis->fe) {
24125aee3deSMauro Carvalho Chehab 		dvb_unregister_frontend(mantis->fe);
24225aee3deSMauro Carvalho Chehab 		dvb_frontend_detach(mantis->fe);
24325aee3deSMauro Carvalho Chehab 	}
24425aee3deSMauro Carvalho Chehab err4:
24525aee3deSMauro Carvalho Chehab 	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
24625aee3deSMauro Carvalho Chehab 
24725aee3deSMauro Carvalho Chehab err3:
24825aee3deSMauro Carvalho Chehab 	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
24925aee3deSMauro Carvalho Chehab 
25025aee3deSMauro Carvalho Chehab err2:
25125aee3deSMauro Carvalho Chehab 	dvb_dmxdev_release(&mantis->dmxdev);
25225aee3deSMauro Carvalho Chehab 
25325aee3deSMauro Carvalho Chehab err1:
25425aee3deSMauro Carvalho Chehab 	dvb_dmx_release(&mantis->demux);
25525aee3deSMauro Carvalho Chehab 
25625aee3deSMauro Carvalho Chehab err0:
25725aee3deSMauro Carvalho Chehab 	dvb_unregister_adapter(&mantis->dvb_adapter);
25825aee3deSMauro Carvalho Chehab 
25925aee3deSMauro Carvalho Chehab 	return result;
26025aee3deSMauro Carvalho Chehab }
26125aee3deSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(mantis_dvb_init);
26225aee3deSMauro Carvalho Chehab 
mantis_dvb_exit(struct mantis_pci * mantis)2634c62e976SGreg Kroah-Hartman int mantis_dvb_exit(struct mantis_pci *mantis)
26425aee3deSMauro Carvalho Chehab {
26525aee3deSMauro Carvalho Chehab 	int err;
26625aee3deSMauro Carvalho Chehab 
26725aee3deSMauro Carvalho Chehab 	if (mantis->fe) {
26825aee3deSMauro Carvalho Chehab 		/* mantis_ca_exit(mantis); */
26925aee3deSMauro Carvalho Chehab 		err = mantis_frontend_shutdown(mantis);
27025aee3deSMauro Carvalho Chehab 		if (err != 0)
27125aee3deSMauro Carvalho Chehab 			dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err);
27225aee3deSMauro Carvalho Chehab 		dvb_unregister_frontend(mantis->fe);
27325aee3deSMauro Carvalho Chehab 		dvb_frontend_detach(mantis->fe);
27425aee3deSMauro Carvalho Chehab 	}
27525aee3deSMauro Carvalho Chehab 
27625aee3deSMauro Carvalho Chehab 	tasklet_kill(&mantis->tasklet);
27725aee3deSMauro Carvalho Chehab 	dvb_net_release(&mantis->dvbnet);
27825aee3deSMauro Carvalho Chehab 
27925aee3deSMauro Carvalho Chehab 	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
28025aee3deSMauro Carvalho Chehab 	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
28125aee3deSMauro Carvalho Chehab 
28225aee3deSMauro Carvalho Chehab 	dvb_dmxdev_release(&mantis->dmxdev);
28325aee3deSMauro Carvalho Chehab 	dvb_dmx_release(&mantis->demux);
28425aee3deSMauro Carvalho Chehab 
28525aee3deSMauro Carvalho Chehab 	dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter");
28625aee3deSMauro Carvalho Chehab 	dvb_unregister_adapter(&mantis->dvb_adapter);
28725aee3deSMauro Carvalho Chehab 
28825aee3deSMauro Carvalho Chehab 	return 0;
28925aee3deSMauro Carvalho Chehab }
29025aee3deSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(mantis_dvb_exit);
291